home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994 February: Tool Chest / Dev.CD Feb 94.toast / Tool Chest / Development Platforms / AppsToGo / AppsToGo.src / DTS.Lib / Utilities.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-06-18  |  81.1 KB  |  3,031 lines  |  [TEXT/MPS ]

  1. /*
  2. **    Apple Macintosh Developer Technical Support
  3. **
  4. **    Collection of Utilities for DTS Sample code
  5. **
  6. **    File:        Utilities.c
  7. **
  8. **    Copyright © 1988-1993 Apple Computer, Inc.
  9. **    All rights reserved.
  10. */
  11.  
  12. /* You may incorporate this sample code into your applications without
  13. ** restriction, though the sample code has been provided "AS IS" and the
  14. ** responsibility for its operation is 100% yours.  However, what you are
  15. ** not permitted to do is to redistribute the source as "DSC Sample Code"
  16. ** after having made changes. If you're going to re-distribute the source,
  17. ** we require that you make it clear in the source that the code was
  18. ** descended from Apple Sample Code, but that you've made changes. */
  19.  
  20.  
  21. #ifndef THINK_C
  22.  
  23. #ifndef __CONTROLS__
  24. #include <Controls.h>
  25. #endif
  26.  
  27. #ifndef __DESK__
  28. #include <Desk.h>
  29. #endif
  30.  
  31. #ifndef __DEVICES__
  32. #include <Devices.h>
  33. #endif
  34.  
  35. #ifndef __EVENTS__
  36. #include <Events.h>
  37. #endif
  38.  
  39. #ifndef __FONTS__
  40. #include <Fonts.h>
  41. #endif
  42.  
  43. #ifndef __MENUS__
  44. #include <Menus.h>
  45. #endif
  46.  
  47. #ifndef __NOTIFICATION__
  48. #include <Notification.h>
  49. #endif
  50.  
  51. #ifndef __OSEVENTS__
  52. #include <OSEvents.h>
  53. #endif
  54.  
  55. #ifndef __RESOURCES__
  56. #include <Resources.h>
  57. #endif
  58.  
  59. #ifndef __SCRIPT__
  60. #include <Script.h>
  61. #endif
  62.  
  63. #ifndef __STDLIB__
  64. #include <StdLib.h>
  65. #endif
  66.  
  67. #ifndef __SEGLOAD__
  68. #include <SegLoad.h>
  69. #endif
  70.  
  71. #ifndef __STRINGS__
  72. #include <Strings.h>
  73. #endif
  74.  
  75. #ifndef __SYSEQU__
  76. #include <SysEqu.h>
  77. #endif
  78.  
  79. #ifndef __TEXTEDIT__
  80. #include <TextEdit.h>
  81. #endif
  82.  
  83. #ifndef __TOOLUTILS__
  84. #include <ToolUtils.h>
  85. #endif
  86.  
  87. #endif    /* Think C */
  88.  
  89. #ifndef __APPLEEVENTS__
  90. #include <AppleEvents.h>
  91. #endif
  92.  
  93. #ifndef __COMPONENTS__
  94. #include <Components.h>
  95. #endif
  96.  
  97. #ifndef __FIXMATH__
  98. #include <FixMath.h>
  99. #endif
  100.  
  101. #ifndef __GESTALTEQU__
  102. #include <GestaltEqu.h>
  103. #endif
  104.  
  105. #ifndef __FOLDERS__
  106. #include <Folders.h>
  107. #endif
  108.  
  109. #ifndef __MOVIES__
  110. #include <Movies.h>
  111. #endif
  112.  
  113. #ifndef __PACKAGES__
  114. #include <Packages.h>
  115. #endif
  116.  
  117. #ifndef __PALETTES__
  118. #include <Palettes.h>
  119. #endif
  120.  
  121. #ifndef __STDDEF__
  122. #include <StdDef.h>
  123. #endif
  124.  
  125. #ifndef __STRING__
  126. #include <String.h>
  127. #endif
  128.  
  129. #ifndef __TRAPS__
  130. #include <Traps.h>
  131. #endif
  132.  
  133. #include "Utilities.h"
  134.  
  135.  
  136.  
  137. /*****************************************************************************/
  138.  
  139.  
  140.  
  141. /* Global variables -- See Utilities.h for more explanation. */
  142.  
  143. short            gMachineType;            /* which machine this is */
  144. short            gSystemVersion;            /* System version number */
  145. short            gProcessorType;            /* which CPU this is */
  146. Boolean            gHasFPU;                /* true if machine has an FPU */
  147. short            gQDVersion;                /* major QD version #; 0 for original,
  148.                                                     1 for color QD, 2 for 32-bit QD */
  149. short            gKeyboardType;            /* which type of keyboard is present */
  150. short            gAppleTalkVersion;        /* AppleTalk version number */
  151. Boolean            gHasPMMU;                /* true if machine has a PMMU or equivalent */
  152. short            gAUXVersion;            /* major A/UX version number (0 if not present) */
  153.  
  154. Boolean            gHasWaitNextEvent;
  155. short            gAppResRef;
  156. Boolean            gInBackground;
  157. Str255            gAppName;
  158. OSType            gSignature = '????';
  159. Boolean            gHaveSystemInfo;
  160.  
  161. long            gQTVersion;                    /* QuickTime version (0 means not available). */
  162. Component        gMovieControllerComponent;    /* QuickTime movie controller component reference. */
  163.                                             /* Call InitQuickTime to initialize these globals. */
  164.  
  165. WindowTemplate    gWindowTemplate;
  166. WindowTemplate    gOpenedWindowTemplate;
  167. ControlHandle    gWhichCtlHit;
  168. long            gWhichCtlWhen;
  169. Boolean            gWhichCtlDbl;
  170. Boolean            gWhichCtlTracking;
  171.  
  172. static Handle    gScrollProc;
  173. static Handle    gButtonProcs[radioButProc + useWFont + 1];
  174. static Rect        gWindowPlacementRect;
  175.  
  176.  
  177.  
  178. /*****************************************************************************/
  179.  
  180.  
  181.  
  182. #pragma segment UtilMain
  183. Rect    SetWindowPlacementRect(Rect *rct)
  184. {
  185.     Rect    r;
  186.  
  187.     r = gWindowPlacementRect;
  188.     if (rct) gWindowPlacementRect = *rct;
  189.     return(r);
  190. }
  191.  
  192.  
  193.  
  194. /*****************************************************************************/
  195.  
  196.  
  197.  
  198. /* Given an alert ID and a window pointer the alert relates to, this function
  199. ** will center the alert’s rectangle before showing it on the proper screen.
  200. ** This follows the Apple Human Interface Guidelines for where to place a
  201. ** centered window on the screen.  If the alert is not closely associated with
  202. ** another window, pass a nil for the window pointer of the related window.  If
  203. ** you pass a nil, the alert is simply displayed where the resource
  204. ** would indicate.  Note that if an error occurs when getting the resource for
  205. ** the alert, then the alert is not displayed, and the returned value is not
  206. ** the item hit, but is the error that occured when reading the resource. */
  207.  
  208. #pragma segment UtilMain
  209. short    CenteredAlert(short alertID, WindowPtr relatedWindow, ModalFilterProcPtr filter)
  210. {
  211.     AlertTHndl    alertHandle;
  212.     WindowPtr    tempWindow;
  213.     Rect        alertRect, sizeInfo;
  214.     short        itemHit;
  215.     char        hstate;
  216.     OSErr        err;
  217.  
  218.     itemHit = 1;
  219.  
  220.     if (!SimpleCanDialog()) {
  221.         alertHandle = (AlertTHndl)GetAppResource('ALRT', alertID, &err);
  222.         if (err) return((short)err);
  223.  
  224.         hstate = LockHandleHigh((Handle)alertHandle);
  225.             /* Do our part to help prevent fragmentation. */
  226.  
  227.         alertRect = (*alertHandle)->boundsRect;
  228.             /* Preserve the real alert bounding rectangle. */
  229.  
  230.         if (tempWindow = NewWindow(nil, &alertRect, "\p", false, dBoxProc,
  231.                                   (WindowPtr)nil, false, 0)) {
  232.             /* Use an invisible temporary window to calculate where the alert will go. */
  233.  
  234.             SetRect(&sizeInfo, 0, 0, 0, 0);
  235.             (*alertHandle)->boundsRect = CenterWindow(tempWindow, relatedWindow, sizeInfo);
  236.             DisposeWindow(tempWindow);
  237.         }
  238.  
  239.         itemHit = Alert(alertID, filter);
  240.  
  241.         (*alertHandle)->boundsRect = alertRect;
  242.             /* Restore the resource's bounding rect, so if this resource is ever used
  243.             ** not through this function, it will open where the resource indicates. */
  244.  
  245.         HSetState((Handle)alertHandle, hstate);
  246.     }
  247.  
  248.     return(itemHit);
  249. }
  250.  
  251.  
  252.  
  253. /*****************************************************************************/
  254.  
  255.  
  256.  
  257. /* Given two rects, this function centers the second one within the first. */
  258.  
  259. #pragma segment UtilMain
  260. void    CenterRectInRect(Rect outerRect, Rect *innerRect)
  261. {
  262.     PositionRectInRect(outerRect, innerRect, FixRatio(1, 2), FixRatio(1, 2));
  263. }
  264.  
  265.  
  266.  
  267. /*****************************************************************************/
  268.  
  269.  
  270.  
  271. /* Center a window within a particular device.  The device to center the window
  272. ** within is determined by passing a related window.  This allows related
  273. ** windows to be kept on the same device.  This is useful if an alert is related
  274. ** to a specific window, for example. */
  275.  
  276. #pragma segment UtilMain
  277. Rect    CenterWindow(WindowPtr window, WindowPtr relatedWindow, Rect sizeInfo)
  278. {
  279.     WindowPtr    whichDevice;
  280.     Rect        deviceRect, oldWindowRect, newWindowRect, contentRect;
  281.     short        h, v, hh, vv;
  282.  
  283.     if (!(whichDevice = relatedWindow))
  284.         whichDevice = window;
  285.             /* If we have a window to center against, use the device for that window,
  286.             ** else use the device for the window that is getting centered. */
  287.  
  288.     deviceRect = GetWindowDeviceRectNMB(whichDevice);
  289.         /* We now have the rectangle of the device we want to center within. */
  290.  
  291.     if (!EmptyRect(&gWindowPlacementRect))
  292.         deviceRect = gWindowPlacementRect;
  293.  
  294.     contentRect = GetWindowContentRect(window);        /* Get where the window is now. */
  295.     h = hh = contentRect.right  - contentRect.left;
  296.     v = vv = contentRect.bottom - contentRect.top;
  297.     if (sizeInfo.left)
  298.         if (h < sizeInfo.left)
  299.             h = sizeInfo.left;
  300.     if (sizeInfo.right)
  301.         if (h > sizeInfo.right)
  302.             h = sizeInfo.right;
  303.     if (sizeInfo.top)
  304.         if (v < sizeInfo.top)
  305.             v = sizeInfo.top;
  306.     if (sizeInfo.bottom)
  307.         if (v > sizeInfo.bottom)
  308.             v = sizeInfo.bottom;
  309.     contentRect.right  = contentRect.left + h;
  310.     contentRect.bottom = contentRect.top  + v;
  311.  
  312.     oldWindowRect = GetWindowStructureRect(window);
  313.     oldWindowRect.right  += (h - hh);
  314.     oldWindowRect.bottom += (v - vv);
  315.     newWindowRect = oldWindowRect;
  316.  
  317.     PositionRectInRect(deviceRect, &newWindowRect, FixRatio(1, 2), FixRatio(1, 3));
  318.         /* Figure out the new window strucRect so we can compare it against
  319.         ** the old strucRect.  This will tell us how much to move the window. */
  320.  
  321.     OffsetRect(&contentRect, newWindowRect.left - oldWindowRect.left,
  322.                             newWindowRect.top  - oldWindowRect.top);
  323.         /* Calculate the new content rect. */
  324.  
  325.     MoveWindow(window, contentRect.left, contentRect.top, false);
  326.         /* Move the window to the new location. */
  327.  
  328.     return(contentRect);
  329. }
  330.  
  331.  
  332.  
  333. /*****************************************************************************/
  334.  
  335.  
  336.  
  337. /* Close a window.  This handles desk accessory and application windows.  Use
  338. ** this call (instead of DisposeAnyWindow) if the memory for the window was
  339. ** allocated by you.  (Same as CloseWindow v.s. DisposeWindow.) */
  340.  
  341. #pragma segment UtilMain
  342. void    CloseAnyWindow(WindowPtr window)
  343. {
  344.     if (IsDAWindow(window))
  345.         CloseDeskAcc(((WindowPeek)window)->windowKind);
  346.     else {
  347.         if (IsAppWindow(window))
  348.             CloseWindow(window);
  349.         else if (((WindowPeek)window)->windowKind >= dialogKind)
  350.             CloseDialog((DialogPtr)window);
  351.     }
  352. }
  353.  
  354.  
  355.  
  356. /*****************************************************************************/
  357.  
  358.  
  359.  
  360. /* Dispose a window.  This handles desk accessory and application windows.  Use
  361. ** this call (instead of CloseAnyWindow) if you want the memory for the window
  362. ** record to be disposed of.  (Same as CloseWindow v.s. DisposeWindow.) */
  363.  
  364. #pragma segment UtilMain
  365. void    DisposeAnyWindow(WindowPtr window)
  366. {
  367.     if (IsDAWindow(window))
  368.         CloseDeskAcc(((WindowPeek)window)->windowKind);
  369.     else {
  370.         if (IsAppWindow(window))
  371.             DisposeWindow(window);
  372.         else if (((WindowPeek)window)->windowKind >= dialogKind)
  373.             DisposDialog((DialogPtr)window);
  374.     }
  375. }
  376.  
  377.  
  378.  
  379. /*****************************************************************************/
  380.  
  381.  
  382.  
  383. /* Display an alert that tells the user an error occurred, then exit the
  384. ** program.  This function is used as an ultimate bail-out for serious errors
  385. ** that prohibit the continuation of the application.  Errors that do not
  386. ** require the termination of the application should be handled in a different
  387. ** manner. */
  388.  
  389. #pragma segment UtilMain
  390. void    DeathAlert(short errResID, short errStringIndex)
  391. {
  392.     ErrorAlert(errResID, errStringIndex);
  393.     ExitToShell();
  394. }
  395.  
  396.  
  397.  
  398. /*****************************************************************************/
  399.  
  400.  
  401.  
  402. /* Display an alert that tells the user an error occurred, then exit the
  403. ** program.  This function is used as an ultimate bail-out for serious errors
  404. ** that prohibit the continuation of the application.  Errors that do not
  405. ** require the termination of the application should be handled in a different
  406. ** manner.  The message parameter is an error code that is to be displayed. */
  407.  
  408. #pragma segment UtilMain
  409. void    DeathAlertMessage(short errResID, short errStringIndex, short message)
  410. {
  411.     ErrorAlertMessage(errResID, errStringIndex, message);
  412.     ExitToShell();
  413. }
  414.  
  415.  
  416.  
  417. /*****************************************************************************/
  418.  
  419.  
  420.  
  421. /* Display an alert that tells the user an error occurred. */
  422.  
  423. #pragma segment UtilMain
  424. void    ErrorAlert(short errResID, short errStringIndex)
  425. {
  426.     ErrorAlertMessage(errResID, errStringIndex, 0);
  427. }
  428.  
  429.  
  430.  
  431. /*****************************************************************************/
  432.  
  433.  
  434.  
  435. /* Display an alert to inform the user of an error.  errStringIndex acts as an
  436. ** index into a STR# resource of error messages.  If no errStringIndex is
  437. ** given, i.e. = 0, then use a standard message.  If message is not noErr then
  438. ** display it as well.
  439. **
  440. ** BUG NOTE:  GetIndString returns a bogus String if the index is
  441. **            not positive. */
  442.  
  443. #pragma segment UtilMain
  444. void    ErrorAlertMessage(short errResID, short errStringIndex, short message)
  445. {
  446.     Str255    msg1, msg2;
  447.  
  448.     SetCursor(&QD(arrow));
  449.  
  450.     if (errStringIndex <= 0) {
  451.         errStringIndex = eStandardErr;
  452.         errResID = rUtilStrings;
  453.     }
  454.     GetIndString(msg1, errResID, errStringIndex);
  455.  
  456.     if (message == noErr) {
  457.         ParamText(msg1, "\p", "\p", "\p");
  458.         CenteredAlert(rUtilErrorAlert, nil, nil);
  459.     } else {
  460.         NumToString(message, msg2);
  461.         ParamText(msg1, msg2, "\p", "\p");
  462.         CenteredAlert(rUtilErrorMessageAlert, nil, nil);
  463.     }
  464. }
  465.  
  466.  
  467.  
  468. /*****************************************************************************/
  469.  
  470.  
  471.  
  472. /* FindSysFolder returns the (real) vRefNum, and the DirID of the current
  473. ** system folder.  It uses the Folder Manager if present, otherwise it falls
  474. ** back to SysEnvirons.  It returns zero on success, otherwise a standard
  475. ** system error. */
  476.  
  477. #pragma segment UtilMain
  478. OSErr    FindSysFolder(short *foundVRefNum, long *foundDirID)
  479. {
  480.     long            gesResponse;
  481.     SysEnvRec        envRec;
  482.     WDPBRec            myWDPB;
  483.     unsigned char    volName[34];
  484.     OSErr            err;
  485.  
  486.     *foundVRefNum = 0;
  487.     *foundDirID = 0;
  488.     if (!Gestalt(gestaltFindFolderAttr, &gesResponse) &&
  489.         BTstQ(gesResponse, gestaltFindFolderPresent)) {        /* Does Folder Manager exist? */
  490.             err = FindFolder(kOnSystemDisk, kSystemFolderType, kDontCreateFolder,
  491.                 foundVRefNum, foundDirID);
  492.     } else {
  493.         /* Gestalt can't give us the answer, so we resort to SysEnvirons */
  494.         if (!(err = SysEnvirons(curSysEnvVers, &envRec))) {
  495.             myWDPB.ioVRefNum = envRec.sysVRefNum;
  496.             volName[0] = '\000';                    /* Zero volume name */
  497.             myWDPB.ioNamePtr = volName;
  498.             myWDPB.ioWDIndex = 0;
  499.             myWDPB.ioWDProcID = 0;
  500.             if (!(err = PBGetWDInfo(&myWDPB, 0))) {
  501.                 *foundVRefNum = myWDPB.ioWDVRefNum;
  502.                 *foundDirID = myWDPB.ioWDDirID;
  503.             }
  504.         }
  505.     }
  506.     return(err);
  507. }
  508.  
  509.  
  510.  
  511. /*****************************************************************************/
  512.  
  513.  
  514.  
  515. /* GetAppIndResource gets a resource from the application's resource file
  516. ** by index. */
  517.  
  518. #pragma segment UtilMain
  519. Handle    GetAppIndResource(ResType theType, short index, OSErr *err)
  520. {
  521.     short    savedResFile;
  522.     Handle    returnHandle;
  523.  
  524.     savedResFile = CurResFile();
  525.     UseResFile(gAppResRef);
  526.     returnHandle = Get1IndResource(theType, index);
  527.     if (err) *err = ResError();
  528.     UseResFile(savedResFile);
  529.     return(returnHandle);
  530. }
  531.  
  532.  
  533.  
  534. /*****************************************************************************/
  535.  
  536.  
  537.  
  538. /* GetAppNamedResource gets a resource from the application's resource file
  539. ** by name. */
  540.  
  541. #pragma segment UtilMain
  542. Handle    GetAppNamedResource(ResType theType, StringPtr name, OSErr *err)
  543. {
  544.     short    savedResFile;
  545.     Handle    returnHandle;
  546.  
  547.     savedResFile = CurResFile();
  548.     UseResFile(gAppResRef);
  549.     returnHandle = Get1NamedResource(theType, name);
  550.     if (err) *err = ResError();
  551.     UseResFile(savedResFile);
  552.     return(returnHandle);
  553. }
  554.  
  555.  
  556.  
  557. /*****************************************************************************/
  558.  
  559.  
  560.  
  561. /* GetAppResource gets a resource from the application's resource file by
  562. ** resource ID. */
  563.  
  564. #pragma segment UtilMain
  565. Handle    GetAppResource(ResType theType, short theID, OSErr *err)
  566. {
  567.     short    savedResFile;
  568.     Handle    returnHandle;
  569.  
  570.     savedResFile = CurResFile();
  571.     UseResFile(gAppResRef);
  572.     returnHandle = Get1Resource(theType, theID);
  573.     if (err) *err = ResError();
  574.     UseResFile(savedResFile);
  575.     return(returnHandle);
  576. }
  577.  
  578.  
  579.  
  580. /*****************************************************************************/
  581.  
  582.  
  583.  
  584. /* Checks for the presence of A/UX by whatever means is appropriate.  Returns
  585. ** the major version number of A/UX (i.e. 0 if A/UX is not present, 1 for
  586. ** any 1.x.x version 2 for any 2.x version, etc.
  587. **
  588. ** This code should work for all past, present and future A/UX systems. */
  589.  
  590. #define HWCfgFlags    0xB22    /* Low memory global used to check if A/UX is running */
  591.  
  592. #pragma segment UtilMain
  593. short    GetAUXVersion(void)
  594. {
  595.     long    auxVersion;
  596.     short    err;
  597.     short    *flagPtr;
  598.  
  599.     /* This code assumes the Gestalt glue checks for the presence of the _Gestalt
  600.     ** trap and does something intelligent if the trap is unavailable, i.e.
  601.     ** return unknown selector. */
  602.  
  603.     auxVersion = 0;
  604.     err = Gestalt(gestaltAUXVersion, &auxVersion);
  605.  
  606.     /* If gestaltUnknownErr or gestaltUndefSelectorErr was returned, then either
  607.     ** we weren't running on A/UX, or the _Gestalt trap is unavailable so use
  608.     ** HWCfgFlags instead.
  609.     ** All other errors are ignored (implies A/UX not present). */
  610.  
  611.     if (err == gestaltUnknownErr || err == gestaltUndefSelectorErr) {    /* Use HWCfgFlags */
  612.         flagPtr = (short *) HWCfgFlags;
  613.         if (BTstQ(*flagPtr, 9))
  614.             auxVersion = 0x100;            /* Do Have A/UX, so assume version 1.x.x */
  615.     }
  616.  
  617.     /* Now right shift auxVersion by 8 bits to get major version number. */
  618.  
  619.     auxVersion >>= 8;
  620.     return((short)auxVersion);
  621. }
  622.  
  623.  
  624.  
  625. /*****************************************************************************/
  626.  
  627.  
  628.  
  629. #pragma segment UtilMain
  630. OSErr    SimpleCanDialog(void)
  631. {
  632.     OSErr                err;
  633.     ProcessSerialNumber    cpsn, fpsn;
  634.     Boolean                procsSame;
  635.  
  636.     err = noErr;
  637.     if (gSystemVersion >= 0x0700) {
  638.         err = AEInteractWithUser(kAEDefaultTimeout, nil, nil);
  639.             /* Ask the AppleEvent Manager if we can come forward */
  640.         GetCurrentProcess(&cpsn);        /* We may have been moved to the front. */
  641.         GetFrontProcess(&fpsn);
  642.         SameProcess(&cpsn, &fpsn, &procsSame);
  643.         gInBackground = !procsSame;
  644.     }
  645.  
  646. /* Three results are possible here....
  647. **   noErr
  648. **     If the call completes with noErr, you can assume that you are
  649. **     (or have been made) the frontmost application, and you are free
  650. **     to interact with the user as much as you'd like.  Put up dialogs,
  651. **     flash alerts, whatever.
  652. **     If you were already in the foreground, AEInteractWithUser
  653. **     immediatly returns with a noErr, so you _should_ always call it.
  654. **
  655. **   errAETimeout
  656. **     If you pass a timeout value, or kAEDefaultTimeout, it is possible
  657. **     for the AEInteractWithUser call to timeout and return control to
  658. **     you before any state change has happened, you are still in the background.
  659. **     What you do at this point is a design decision you'll have to make.
  660. **     You can re-post the AEInteract call, perhaps with a larger timeout
  661. **     or kNoTimeOut, and see if you come forward this time.
  662. **     Or, you can continue on knowing that you are in the background and
  663. **     not interact at all.
  664. **
  665. **   errAENoUserInteraction
  666. **     If you get this error code back, this means that you
  667. **     MUST NOT interact with the user.  Do NOT put up any dialogs, alerts,
  668. **     or cause any other action that requires direct user intervention.
  669. **     This error code will be returned, for example, if any application
  670. **     has used the AESetInteractionAllowed call to specify no interaction,
  671. **     or if there is a pending AppleEvent that has interaction denied.
  672. **     This will also be returned if your application is being run by
  673. **     a script system, since an AppleEvent script cannot press buttons.
  674. **     By the way, if this is the case the AEinteractWithUser call has
  675. **     also not posted the notification.
  676. */
  677.  
  678.     return(err);
  679. }
  680.  
  681.  
  682.  
  683. /*****************************************************************************/
  684.  
  685.  
  686.  
  687. /* Given a dialog ID and a window pointer the dialog relates to, this function
  688. ** will center the dialog’s rectangle before showing it on the proper screen.
  689. ** This follows the Apple Human Interface Guidelines for where to place a
  690. ** centered window on the screen.  If the dialog is not closely associated with
  691. ** another window, pass a nil for the window pointer of the related window.  If
  692. ** you pass a nil, the dialog is simply displayed where the resource
  693. ** would indicate. */
  694.  
  695. #pragma segment UtilMain
  696. DialogPtr    GetCenteredDialog(short id, DialogPtr storage, WindowPtr relatedWindow, WindowPtr behind)
  697. {
  698.     DialogTHndl    dlogResource;
  699.     DialogPtr    dialog;
  700.     Boolean        oldVis;
  701.     char        hstate;
  702.     OSErr        err;
  703.     Rect        sizeInfo;
  704.  
  705.     dialog = nil;
  706.     if (!SimpleCanDialog()) {
  707.         if (dlogResource = (DialogTHndl)GetAppResource('DLOG', id, &err)) {
  708.             hstate = LockHandleHigh((Handle)dlogResource);
  709.             oldVis = (*dlogResource)->visible;
  710.             (*dlogResource)->visible = false;
  711.             if (dialog = GetNewDialog(id, storage, behind)) {
  712.                 SetRect(&sizeInfo, 0, 0, 0, 0);
  713.                 CenterWindow(dialog, relatedWindow, sizeInfo);
  714.                 if (oldVis)
  715.                     ShowWindow(dialog);
  716.             }
  717.             (*dlogResource)->visible = oldVis;
  718.             HSetState((Handle)dlogResource, hstate);
  719.         }
  720.     }
  721.     return(dialog);
  722. }
  723.  
  724.  
  725.  
  726. /*****************************************************************************/
  727.  
  728.  
  729.  
  730. /* Given a window ID and a window pointer the window relates to, this function
  731. ** will center the window’s rectangle before showing it on the proper screen.
  732. ** This follows the Apple Human Interface Guidelines for where to place a
  733. ** centered window on the screen.  If the window is not closely associated with
  734. ** another window, pass a nil for the window pointer of the related window.  If
  735. ** you pass a nil, the window is simply displayed where the resource
  736. ** would indicate. */
  737.  
  738. #pragma segment UtilMain
  739. WindowPtr    GetCenteredWindow(short id, Ptr storage, Boolean vis, WindowPtr relWindow,
  740.                               WindowPtr behind, Boolean inColor, Rect sizeInfo, long refCon)
  741. {
  742.     return(GetSomeKindOfWindow(CenterWindow, id, storage, vis, relWindow,
  743.                                behind, inColor, sizeInfo, refCon));
  744. }
  745.  
  746.  
  747.  
  748. /*****************************************************************************/
  749.  
  750.  
  751.  
  752. /* GetGestaltResult returns the result value from Gestalt for the specified
  753. ** selector.  If Gestalt returned an error GetGestaltResult returns zero.
  754. ** Use of this function is only cool if we don't care whether Gestalt returned
  755. ** an error.  In many cases you may need to know the exact Gestalt error code
  756. ** so then this function would be inappropriate.
  757. ** See GetAUXVersion for an example. */
  758.  
  759. #pragma segment UtilMain
  760. long    GetGestaltResult(OSType gestaltSelector)
  761. {
  762.     long    gestaltResult;
  763.  
  764.     if (Gestalt(gestaltSelector, &gestaltResult) == noErr)
  765.         return(gestaltResult);
  766.     else
  767.         return(0);
  768. }
  769.  
  770.  
  771.  
  772. /*****************************************************************************/
  773.  
  774.  
  775.  
  776. /* Get the global coordinates of the mouse.  When you call OSEventAvail it will
  777. ** return either a pending event or a null event.  In either case, the where
  778. ** field of the event record will contain the current position of the mouse in
  779. ** global coordinates and the modifiers field will reflect the current state of
  780. ** the modifiers.  Another way to get the global coordinates is to call
  781. ** GetMouse and LocalToGlobal, but that requires being sure that the port is set
  782. ** to a valid port. */
  783.  
  784. #pragma segment UtilMain
  785. Point    GetGlobalMouse(void)
  786. {
  787.     EventRecord    event;
  788.  
  789.     OSEventAvail(kNoEvents, &event);    /* we aren’t interested in any events */
  790.     return(event.where);                /* just the mouse position */
  791. }
  792.  
  793.  
  794.  
  795. /*****************************************************************************/
  796.  
  797.  
  798.  
  799. /* Given a window, this will return the top left point of the window’s port in
  800. ** global coordinates.  Something this doesn’t include is the window’s drag
  801. ** region (or title bar).  This returns the top left point of the window’s
  802. ** content area only. */
  803.  
  804. #pragma segment UtilMain
  805. Point    GetGlobalTopLeft(WindowPtr window)
  806. {
  807.     GrafPtr    oldPort;
  808.     Point    globalPt;
  809.  
  810.     GetPort(&oldPort);
  811.     SetPort(window);
  812.     globalPt = TopLeft(window->portRect);
  813.     LocalToGlobal(&globalPt);
  814.     SetPort(oldPort);
  815.     return(globalPt);
  816. }
  817.  
  818.  
  819.  
  820. /*****************************************************************************/
  821.  
  822.  
  823.  
  824. /* Return the amount of free space on the volume in KBytes. -1 is returned as
  825. ** the size if there is an error. */
  826.  
  827. #pragma segment UtilMain
  828. long    GetKFreeSpace(short vRefNum)
  829. {
  830.     HParamBlockRec    pb;
  831.     OSErr            err;
  832.  
  833.     pb.volumeParam.ioNamePtr = nil;            /* we don't care about the name */
  834.     pb.volumeParam.ioVRefNum = vRefNum;
  835.     pb.volumeParam.ioVolIndex = 0;            /* use ioVRefNum only */
  836.     err = PBHGetVInfo(&pb, false);
  837.  
  838.     if (err == noErr)
  839.         return((pb.volumeParam.ioVFrBlk * pb.volumeParam.ioVAlBlkSiz) / 1024);
  840.     else
  841.         return(-1);
  842. }
  843.  
  844.  
  845.  
  846. /*****************************************************************************/
  847.  
  848.  
  849.  
  850. #pragma segment UtilMain
  851. Rect    GetMainScreenRect(void)
  852. {
  853.     GDHandle    mainDevice;
  854.     GrafPtr        mainPort;
  855.  
  856.     if (gQDVersion > kQDOriginal) {
  857.         mainDevice = GetMainDevice();
  858.         return((*mainDevice)->gdRect);
  859.     }
  860.     else {
  861.         GetWMgrPort(&mainPort);
  862.         return(mainPort->portRect);
  863.     }
  864. }
  865.  
  866.  
  867.  
  868. /*****************************************************************************/
  869.  
  870.  
  871.  
  872. /* Find the greatest overlap device for the given global rectangle. */
  873.  
  874. #pragma segment UtilMain
  875. GDHandle    GetRectDevice(Rect globalRect)
  876. {
  877.     long        area, maxArea;
  878.     GDHandle    device, deviceToReturn;
  879.     Rect        intersection;
  880.  
  881.     deviceToReturn = GetMainDevice();            /* Use as default choice. */
  882.     maxArea = 0;
  883.  
  884.     for (device = GetDeviceList(); device; device = GetNextDevice(device)) {
  885.         if (TestDeviceAttribute(device, screenDevice)
  886.           && TestDeviceAttribute(device, screenActive)
  887.           && SectRect(&globalRect, &((*device)->gdRect), &intersection)) {
  888.             area = ((long)(intersection.right - intersection.left)) *
  889.                    ((long)(intersection.bottom - intersection.top));
  890.             if (area > maxArea) {
  891.                 deviceToReturn = device;
  892.                 maxArea = area;
  893.             }
  894.         }
  895.     }
  896.     return(deviceToReturn);
  897. }
  898.  
  899.  
  900.  
  901. /*****************************************************************************/
  902.  
  903.  
  904.  
  905. /* Find the rect of the greatest overlap device for the given global rect. */
  906.  
  907. #pragma segment UtilMain
  908. Rect    GetRectDeviceRect(Rect globalRect)
  909. {
  910.     if (gQDVersion > kQDOriginal)
  911.         return((*GetRectDevice(globalRect))->gdRect);
  912.     else
  913.         return(GetMainScreenRect());
  914. }
  915.  
  916.  
  917.  
  918. /*****************************************************************************/
  919.  
  920.  
  921.  
  922. /* Given a window positioning procedure pointer, a window ID and a window
  923. ** pointer the window relates to, this function open a new window by either
  924. ** a NewCWindow or a NewWindow call, depending on the value of inColor.  The
  925. ** window will be opened invisible, independent of what the resource says.
  926. ** Once the window is opened successfully, the positioning procedure is
  927. ** called.  The positioning procedure is passed a pointer to the just-opened
  928. ** invisible window and a pointer to the related window.  It is up to the
  929. ** positioning procedure to move the invisible window to the correct location
  930. ** on the correct device.  Once the positioning procedure returns, the window
  931. ** will be made visible if so indicated by the resource. */
  932.  
  933. #pragma segment UtilMain
  934. WindowPtr    GetSomeKindOfWindow(PositionWndProcPtr whatKind, short windID, Ptr storage,
  935.                                 Boolean vis, WindowPtr relatedWindow, WindowPtr behind,
  936.                                 Boolean inColor, Rect sizeInfo, long refCon)
  937. {
  938.     WindowTHndl        windowResource;
  939.     WindowTemplate    wt;
  940.     WindowPtr        window;
  941.     PaletteHandle    wpalette;
  942.     Ptr                allocStg;
  943.     OSErr            err;
  944.  
  945.     window = nil;        /* Assume we will fail.  (Good attitude.) */
  946.     SetRect(&gOpenedWindowTemplate.boundsRect, 0, 0, 0, 0);
  947.  
  948.     if (gQDVersion == kQDOriginal)
  949.         inColor = false;
  950.  
  951.     if (!(allocStg = storage))
  952.         allocStg = NewPtr(sizeof(WindowRecord));
  953.  
  954.     if (allocStg) {            /* If we have memory for the window record... */
  955.  
  956.         wt = gWindowTemplate;
  957.         if (EmptyRect(&wt.boundsRect))
  958.             if (windowResource = (WindowTHndl)GetAppResource('WIND', windID, &err))
  959.                 wt = **windowResource;        /* Make local copy of resource. */
  960.  
  961.         if (!EmptyRect(&wt.boundsRect)) {
  962.             window = (inColor ? NewCWindow(allocStg, &wt.boundsRect,
  963.                                            wt.title, false, wt.procID,
  964.                                            behind, wt.goAwayFlag, wt.refCon)
  965.                                : NewWindow(allocStg, &wt.boundsRect, wt.title,
  966.                                            false, wt.procID,
  967.                                            behind, wt.goAwayFlag, wt.refCon));
  968.                 /* Open either a regular or color window. */
  969.  
  970.             if (window) {        /* If we were able to open a window... */
  971.                 if (inColor)
  972.                     if (wpalette = GetNewPalette(windID))
  973.                         SetPalette(window, wpalette, true);
  974.  
  975.                 SetWRefCon(window, refCon);
  976.                 if (whatKind)
  977.                     (*whatKind)(window, relatedWindow, sizeInfo);
  978.                         /* Call the designated window positioning procedure. */
  979.  
  980.                 if (vis)
  981.                     ShowWindow(window);
  982.                         /* If caller says window should be visible, make it so. */
  983.             }
  984.         }
  985.         if (!window) {
  986.             if (allocStg != storage)
  987.                 DisposPtr(storage);
  988.         }            /* If we failed, then get rid of window record memory. */
  989.         else
  990.             gOpenedWindowTemplate = wt;
  991.     }
  992.  
  993.     return(window);
  994. }
  995.  
  996.  
  997.  
  998. /*****************************************************************************/
  999.  
  1000.  
  1001.  
  1002. /* Given a window ID and a window pointer the window relates to, this function
  1003. ** will stagger the window’s rectangle before showing it on the proper screen.
  1004. ** This follows the Apple Human Interface Guidelines for where to place a
  1005. ** staggered window on the screen.  If the window is not closely associated
  1006. ** with another window, pass a nil for the window pointer of the related
  1007. ** window.  If you pass a nil, the window is simply displayed where the
  1008. ** resource would indicate. */
  1009.  
  1010. #pragma segment UtilMain
  1011. WindowPtr    GetStaggeredWindow(short id, Ptr storage, Boolean vis, WindowPtr relWindow,
  1012.                                WindowPtr behind, Boolean inColor, Rect sizeInfo, long refCon)
  1013. {
  1014.     return(GetSomeKindOfWindow(StaggerWindow, id, storage, vis, relWindow,
  1015.                                behind, inColor, sizeInfo, refCon));
  1016. }
  1017.  
  1018.  
  1019.  
  1020. /*****************************************************************************/
  1021.  
  1022.  
  1023.  
  1024. /*    Check the bits of a trap number to determine its type. */
  1025.  
  1026. #pragma segment UtilMain
  1027. TrapType    GetTrapType(short theTrap)
  1028. {
  1029.     /* OS traps start with A0, Tool with A8 or AA. */
  1030.     if ((theTrap & 0x0800) == 0)                    /* per D.A. */
  1031.         return(OSTrap);
  1032.     else
  1033.         return(ToolTrap);
  1034. }
  1035.  
  1036.  
  1037.  
  1038. /*****************************************************************************/
  1039.  
  1040.  
  1041.  
  1042. /* Given a window pointer, return the global rectangle that encloses the
  1043. ** content area of the window. */
  1044.  
  1045. #pragma segment UtilMain
  1046. Rect    GetWindowContentRect(WindowPtr window)
  1047. {
  1048.     WindowPtr    oldPort;
  1049.     Rect        contentRect;
  1050.  
  1051.     SetRect(&contentRect, 0, 0, 0, 0);
  1052.     if (window) {
  1053.         GetPort(&oldPort);
  1054.         SetPort(window);
  1055.         contentRect = window->portRect;
  1056.         LocalToGlobalRect(&contentRect);
  1057.         SetPort(oldPort);
  1058.     }
  1059.  
  1060.     return(contentRect);
  1061. }
  1062.  
  1063.  
  1064.  
  1065. /*****************************************************************************/
  1066.  
  1067.  
  1068.  
  1069. /* This procedure counts the number of windows in the application plane.
  1070. ** You have the choices of also including DAs and invisible windows in
  1071. ** this count. */
  1072.  
  1073. #pragma segment UtilMain
  1074. short    GetWindowCount(Boolean includeDAs, Boolean includeDLOGs, Boolean includeInvisibles)
  1075. {
  1076.     WindowPeek    window;
  1077.     short        count;
  1078.  
  1079. #ifdef __SYSEQU__
  1080.     for (count = 0, window = *(WindowPeek *)WindowList;
  1081. #else
  1082.     for (count = 0, window = WindowList;
  1083. #endif
  1084.          (window != nil); window = window->nextWindow) {
  1085.  
  1086.         if ((window->windowKind < 0) && (!includeDAs)) continue;
  1087.         if ((window->windowKind < userKind) && (!includeDLOGs)) continue;
  1088.         if ((window->visible) || (includeInvisibles))
  1089.             count++;
  1090.     }
  1091.     return(count);
  1092. }
  1093.  
  1094.  
  1095.  
  1096. /*****************************************************************************/
  1097.  
  1098.  
  1099.  
  1100. /* Find the greatest overlap device for the given window. */
  1101.  
  1102. #pragma segment UtilMain
  1103. GDHandle    GetWindowDevice(WindowPtr window)
  1104. {
  1105.     return(GetRectDevice(GetWindowStructureRect(window)));
  1106. }
  1107.  
  1108.  
  1109.  
  1110. /*****************************************************************************/
  1111.  
  1112.  
  1113.  
  1114. /* Given a window pointer, find the device that contains most of the window
  1115. ** and return the device's bounding rectangle. */
  1116.  
  1117. #pragma segment UtilMain
  1118. Rect    GetWindowDeviceRect(WindowPtr window)
  1119. {
  1120.     if (gQDVersion > kQDOriginal)
  1121.         return((*GetWindowDevice(window))->gdRect);
  1122.     else
  1123.         return(GetMainScreenRect());
  1124. }
  1125.  
  1126.  
  1127.  
  1128. /*****************************************************************************/
  1129.  
  1130.  
  1131.  
  1132. /* Given a window pointer, find the device that contains most of the window
  1133. ** and return the device's bounding rectangle.  If this device is the main
  1134. ** device, then remove the menubar area from the rectangle. */
  1135.  
  1136. #pragma segment UtilMain
  1137. Rect    GetWindowDeviceRectNMB(WindowPtr window)
  1138. {
  1139.     Rect    deviceRect, tempRect;
  1140.  
  1141.     SetRect(&deviceRect, 0, 0, 0, 0);
  1142.  
  1143.     if (window) {
  1144.         deviceRect = GetWindowDeviceRect(window);
  1145.         tempRect = GetMainScreenRect();
  1146.         if (EqualRect(&deviceRect, &tempRect))
  1147.             deviceRect.top += GetMBarHeight();
  1148.     }
  1149.  
  1150.     return(deviceRect);
  1151. }
  1152.  
  1153.  
  1154.  
  1155. /*****************************************************************************/
  1156.  
  1157.  
  1158.  
  1159. /* This procedure is used to get the rectangle that surrounds the entire
  1160. ** structure of a window.  This is true whether or not the window is visible.
  1161. ** If the window is visible, then it is a simple matter of using the bounding
  1162. ** rectangle of the structure region.  If the window is invisible, then the
  1163. ** strucRgn is not correct.  To make it correct, then window has to be moved
  1164. ** way off the screen and then made visible.  This generates a valid strucRgn,
  1165. ** although it is valid for the position that is way off the screen.  It still
  1166. ** needs to be offset back into the original position.  Once the bounding
  1167. ** rectangle for the strucRgn is obtained, the window can then be hidden again
  1168. ** and moved back to its correct location.  Note that ShowHide is used,
  1169. ** instead of ShowWindow and HideWindow.  HideWindow can change the plane of
  1170. ** the window.  Also, ShowHide does not affect the hiliting of windows.
  1171. ** Note that using ShowHide to make the window visible has the unfortunate
  1172. ** side-effect of changing the userState rect.  Since we make the window
  1173. ** invisible prior to moving it back, userState gets left funky.  Due to this,
  1174. ** we have to cache it prior to doing the ShowHide games. */
  1175.  
  1176. #pragma segment UtilMain
  1177. Rect    GetWindowStructureRect(WindowPtr window)
  1178. {
  1179. #define kOffscreenLoc 0x4000
  1180.  
  1181.     GrafPtr    oldPort;
  1182.     Rect    structureRect, userState;
  1183.     Point    windowLoc;
  1184.  
  1185.     SetRect(&structureRect, 0, 0, 0, 0);
  1186.  
  1187.     if (window) {
  1188.  
  1189.         if (((WindowPeek)window)->visible)
  1190.             structureRect = (*(((WindowPeek)window)->strucRgn))->rgnBBox;
  1191.  
  1192.         else {
  1193.             GetPort(&oldPort);
  1194.             SetPort(window);
  1195.             windowLoc  = GetGlobalTopLeft(window);
  1196.             if (((WindowPeek)window)->spareFlag)
  1197.                 userState = (*(WStateDataHandle)(((WindowPeek)window)->dataHandle))->userState;
  1198.             MoveWindow(window, kOffscreenLoc, kOffscreenLoc, false);
  1199.             ShowHide(window, true);
  1200.             structureRect = (*(((WindowPeek)window)->strucRgn))->rgnBBox;
  1201.             ShowHide(window, false);
  1202.             MoveWindow(window, windowLoc.h, windowLoc.v, false);
  1203.             if (((WindowPeek)window)->spareFlag)
  1204.                 (*(WStateDataHandle)(((WindowPeek)window)->dataHandle))->userState = userState;
  1205.             SetPort(oldPort);
  1206.             OffsetRect(&structureRect, windowLoc.h - kOffscreenLoc, windowLoc.v - kOffscreenLoc);
  1207.         }
  1208.     }
  1209.  
  1210.     return(structureRect);
  1211. }
  1212.  
  1213.  
  1214.  
  1215. /*****************************************************************************/
  1216.  
  1217.  
  1218.  
  1219. #pragma segment UtilMain
  1220. void    GlobalToLocalRect(Rect *aRect)
  1221. {
  1222.     GlobalToLocal(&TopLeft(*aRect));
  1223.     GlobalToLocal(&BotRight(*aRect));
  1224. }
  1225.  
  1226.  
  1227.  
  1228. /*****************************************************************************/
  1229.  
  1230.  
  1231.  
  1232. #pragma segment UtilMain
  1233. void    InitToolBox(void)
  1234. {
  1235.     InitGraf((Ptr) &QD(thePort));
  1236.     InitFonts();
  1237.     InitWindows();
  1238.     InitMenus();
  1239.     TEInit();
  1240.     InitDialogs(nil);
  1241.     InitCursor();
  1242. }
  1243.  
  1244.  
  1245.  
  1246. /*****************************************************************************/
  1247.  
  1248.  
  1249.  
  1250. /* GetSystemInfo sets up some global variables for use by the utilities
  1251. ** package and your application.  If you call StandardInitialization, you
  1252. ** don't need to call this, as it will do it for you. */
  1253.  
  1254. #pragma segment UtilMain
  1255. void    GetSystemInfo(void)
  1256. {
  1257.     Handle            apParam;
  1258.     Handle            bndlResource;
  1259.     OSErr            err;
  1260.     short            ignoreRefNum;
  1261.  
  1262.     if (!gHaveSystemInfo) {
  1263.  
  1264.         /* Init all the Gestalt variables */
  1265.         gMachineType   = GetGestaltResult(gestaltMachineType);
  1266.         gSystemVersion = GetGestaltResult(gestaltSystemVersion);
  1267.         gProcessorType = GetGestaltResult(gestaltProcessorType);
  1268.  
  1269.         /* We only concern ourselves with there being an FPU, not which type it is. */
  1270.         gHasFPU = (GetGestaltResult(gestaltFPUType) != gestaltNoFPU);
  1271.  
  1272.         /* We only concern ourselves with the major QD version number
  1273.         ** 0 for original QD, 1 for 8-bit color QD, and 2 for 32-bit QD. */
  1274.  
  1275.         gQDVersion = (GetGestaltResult(gestaltQuickdrawVersion) >> 8) & 0xFF;
  1276.         gKeyboardType = GetGestaltResult(gestaltKeyboardType);
  1277.  
  1278.         if (!OpenDriver("\p.MPP", &ignoreRefNum))
  1279.             gAppleTalkVersion = GetGestaltResult(gestaltAppleTalkVersion);
  1280.                 /* Under system 6, the driver isn't necessarily open, so open it for sure.
  1281.                 ** If the driver isn't opened, then the gestalt selector isn't installed,
  1282.                 ** and therefore returns 0, which isn't really the case. */
  1283.  
  1284.         /* We only concern ourselves with there being an PMMU, not which type it is. */
  1285.         gHasPMMU = GetGestaltResult(gestaltMMUType) >= gestalt68851;
  1286.         gAUXVersion = GetAUXVersion();
  1287.  
  1288.         gHasWaitNextEvent = TrapExists(_WaitNextEvent);
  1289.         gInBackground = false;
  1290.  
  1291.         GetAppParms(gAppName, &gAppResRef, &apParam);
  1292. #ifdef THINK_C
  1293.         gAppResRef = CurResFile();            /* returns refNum of .rsrc file */
  1294.             /* 10/16/90 pvh/MacDTS
  1295.             ** With GetAppParams(), THINK C in project mode returns the project resource
  1296.             ** file AND NOT the .rsrc file, which is what one really wants (trust me).
  1297.             ** If THINK is present we will return CurResFile() which will be the .rsrc
  1298.             ** file instead.  The name will still be the project name in project mode,
  1299.             ** so be aware of that. */
  1300. #endif
  1301.  
  1302.         bndlResource = GetAppIndResource('BNDL', 1, &err);
  1303.         if (bndlResource)
  1304.             gSignature = *(OSType *)(*bndlResource);
  1305.  
  1306.         gHaveSystemInfo = true;
  1307.     }
  1308. }
  1309.  
  1310.  
  1311.  
  1312. /*****************************************************************************/
  1313.  
  1314.  
  1315.  
  1316. /* Check to see if a window belongs to the application.  If the window pointer
  1317. ** passed was nil, then it could not be an application window.  WindowKinds
  1318. ** that are negative belong to the system and windowKinds less than userKind
  1319. ** are reserved by Apple except for windowKinds equal to dialogKind, which
  1320. ** mean it is a dialog. */
  1321.  
  1322. #pragma segment UtilMain
  1323. Boolean    IsAppWindow(WindowPtr window)
  1324. {
  1325.     if (window) return(((WindowPeek)window)->windowKind >= userKind);
  1326.     else        return(false);
  1327. }
  1328.  
  1329.  
  1330.  
  1331. /*****************************************************************************/
  1332.  
  1333.  
  1334.  
  1335. /* Check to see if a window belongs to a desk accessory. */
  1336.  
  1337. #pragma segment UtilMain
  1338. Boolean    IsDAWindow(WindowPtr window)
  1339. {
  1340.     if (window)    /* DA windows have negative windowKinds */
  1341.         return(((WindowPeek) window)->windowKind < 0);
  1342.     else
  1343.         return(false);
  1344. }
  1345.  
  1346.  
  1347.  
  1348. /*****************************************************************************/
  1349.  
  1350.  
  1351.  
  1352. #pragma segment UtilMain
  1353. void    LocalToGlobalRect(Rect *aRect)
  1354. {
  1355.     LocalToGlobal(&TopLeft(*aRect));
  1356.     LocalToGlobal(&BotRight(*aRect));
  1357. }
  1358.  
  1359.  
  1360.  
  1361. /*****************************************************************************/
  1362.  
  1363.  
  1364.  
  1365. #pragma segment UtilMain
  1366. char    LockHandleHigh(Handle theHandle)
  1367. {
  1368.     char    hstate;
  1369.  
  1370.     hstate = HGetState(theHandle);
  1371.     MoveHHi(theHandle);
  1372.     HLock(theHandle);
  1373.     return(hstate);
  1374. }
  1375.  
  1376.  
  1377.  
  1378. /*****************************************************************************/
  1379.  
  1380.  
  1381.  
  1382. /* InitGraf is always implemented (trap $A86E).  If the trap table is big
  1383. ** enough, trap $AA6E will always point to either Unimplemented or some other
  1384. ** trap, but will never be the same as InitGraf.  Thus, you can check the size
  1385. ** of the trap table by asking if the address of trap $A86E is the same as
  1386. ** $AA6E. */
  1387.  
  1388. #pragma segment UtilMain
  1389. short    NumToolboxTraps(void)
  1390. {
  1391.     if (NGetTrapAddress(_InitGraf, ToolTrap) == NGetTrapAddress(0xAA6E, ToolTrap))
  1392.         return(0x200);
  1393.     else
  1394.         return(0x400);
  1395. }
  1396.  
  1397.  
  1398.  
  1399. /*****************************************************************************/
  1400.  
  1401.  
  1402.  
  1403. /* Given two rectangles, this function positions the second within the first
  1404. ** one so that it maintains the spacing specified by the horzRatio and
  1405. ** vertRatio parameters.  In other words, to center an inner rectangle
  1406. ** hoizontally, but have its center be 1/3 from the top of the outer rectangle,
  1407. ** call this function with horzRatio = FixRatio(1, 2), vertRatio =
  1408. ** FixRatio(1, 3).  We use Fixed rather than floating point to avoid
  1409. ** complications when mixing MC68881/non-MC68881 versions of Utilities. */
  1410.  
  1411. #pragma segment UtilMain
  1412. void    PositionRectInRect(Rect outerRect, Rect *innerRect, Fixed horzRatio, Fixed vertRatio)
  1413. {
  1414.     short    outerRectHeight;
  1415.     short    outerRectWidth;
  1416.     short    innerRectHeight;
  1417.     short    innerRectWidth;
  1418.     short    yLocation;
  1419.     short    xLocation;
  1420.  
  1421.     outerRectHeight = outerRect.bottom - outerRect.top;
  1422.     outerRectWidth = outerRect.right - outerRect.left;
  1423.  
  1424.     innerRectHeight = innerRect->bottom - innerRect->top;
  1425.     innerRectWidth = innerRect->right - innerRect->left;
  1426.         yLocation = Fix2Long(FixMul(Long2Fix(outerRectHeight - innerRectHeight), vertRatio))
  1427.             + outerRect.top;
  1428.         xLocation = Fix2Long(FixMul(Long2Fix(outerRectWidth - innerRectWidth), horzRatio))
  1429.             + outerRect.left;
  1430.  
  1431.     innerRect->top = yLocation;
  1432.     innerRect->left = xLocation;
  1433.     innerRect->bottom = yLocation + innerRectHeight;
  1434.     innerRect->right = xLocation + innerRectWidth;
  1435. }
  1436.  
  1437.  
  1438.  
  1439. /*****************************************************************************/
  1440.  
  1441.  
  1442.  
  1443. #pragma segment UtilMain
  1444. void    PullApplicationToFront(void)
  1445. {
  1446. #define kBroughtToFront 3
  1447.  
  1448.     EventRecord event;
  1449.     short        count;
  1450.  
  1451.     for (count = 1; count <= kBroughtToFront; count++)
  1452.         EventAvail(everyEvent, &event);
  1453. }
  1454.  
  1455.  
  1456.  
  1457. /*****************************************************************************/
  1458.  
  1459.  
  1460.  
  1461. /* This algorithm for staggering windows does quite a good job.  It also is
  1462. ** quite gnarly.  Here's the deal:
  1463. ** There are pre-designated positions that we will try when positioning a
  1464. ** window.  These slots will be tried from the upper-left corner towards the
  1465. ** lower-right corner.  If there are other windows in that slot, then we will
  1466. ** consider that slot taken, and proceed to the next slot.  A slot is
  1467. ** determined to be taken by checking a point with a slop area.  This slop
  1468. ** area is diamond-shaped, not simply rectangular.  If there is no other
  1469. ** visible window with an upper-left corner within the slopt diamond, then
  1470. ** we are allowed to position our window there.
  1471. ** The above rule holds true unless this forces the window to be partly
  1472. ** off the screen.  If the window ends up partly off the screen, then we try
  1473. ** a new diagonal just below the first diagonal we tried.  We keep trying
  1474. ** lower and lower diagonals until we find a spot for the window, or the
  1475. ** diagonal doesn't fit on the screen at all.  If the diagonal doesn't fit,
  1476. ** then we try diagonals to the right of the first diagonal.  If even this
  1477. ** doesn't work, then we give up and put the window in the original spot
  1478. ** we tried. */
  1479.  
  1480. #pragma segment UtilMain
  1481. Rect    StaggerWindow(WindowPtr window, WindowPtr relatedWindow, Rect sizeInfo)
  1482. {
  1483.     WindowPtr    whichDevice, staggerFromWindow;
  1484.     Rect        deviceRect, oldWindowRect, newWindowRect, slot1;
  1485.     Rect        testRct1, testRct2, contentRect, staggerFromRect;
  1486.     Point        delta, absdelta;
  1487.     Boolean        contained, vertTry;
  1488.     short        diamondSize, diagNum, tryNum, h, v, hh, vv;
  1489.  
  1490.     if (!(whichDevice = relatedWindow))
  1491.         whichDevice = window;
  1492.             /* If we have a window to stagger from, use the device for that window,
  1493.             ** else use the device for the window that is getting staggered. */
  1494.  
  1495.     deviceRect = GetWindowDeviceRectNMB(whichDevice);
  1496.         /* We now have the rect of the device we want to stagger within. */
  1497.  
  1498.     if (!EmptyRect(&gWindowPlacementRect))
  1499.         deviceRect = gWindowPlacementRect;
  1500.  
  1501.     contentRect = GetWindowContentRect(window);        /* Get where the window is now. */
  1502.     h = hh = contentRect.right  - contentRect.left;
  1503.     v = vv = contentRect.bottom - contentRect.top;
  1504.     if (sizeInfo.left)
  1505.         if (h < sizeInfo.left)
  1506.             h = sizeInfo.left;
  1507.     if (sizeInfo.right)
  1508.         if (h > sizeInfo.right)
  1509.             h = sizeInfo.right;
  1510.     if (sizeInfo.top)
  1511.         if (v < sizeInfo.top)
  1512.             v = sizeInfo.top;
  1513.     if (sizeInfo.bottom)
  1514.         if (v > sizeInfo.bottom)
  1515.             v = sizeInfo.bottom;
  1516.     contentRect.right  = contentRect.left + h;
  1517.     contentRect.bottom = contentRect.top  + v;
  1518.  
  1519.     oldWindowRect = GetWindowStructureRect(window);
  1520.  
  1521.     newWindowRect.top    = deviceRect.top  + kStartPtV;
  1522.     newWindowRect.left   = deviceRect.left + kStartPtH;
  1523.     newWindowRect.bottom = newWindowRect.top  + oldWindowRect.bottom - oldWindowRect.top;
  1524.     newWindowRect.right  = newWindowRect.left + oldWindowRect.right  - oldWindowRect.left;
  1525.     newWindowRect.right  += (h - hh);
  1526.     newWindowRect.bottom += (v - vv);
  1527.         /* We now have a new rect for the first window position slot. */
  1528.  
  1529.     slot1 = newWindowRect;
  1530.         /* We keep this slot in case we find no acceptable slots.  If we
  1531.         ** don't find an acceptable one, we will use this one anyway. */
  1532.  
  1533.     diamondSize = (kStaggerH < kStaggerV) ? kStaggerH : kStaggerV;
  1534.     for (diagNum = 0, vertTry = true;;) {
  1535.         for (tryNum = 0;; ++tryNum) {
  1536.  
  1537.             SectRect(&newWindowRect, &deviceRect, &testRct1);
  1538.             if (!(contained = EqualRect(&newWindowRect, &testRct1))) break;
  1539.                 /* Break if the slot we are testing went off the device. */
  1540.  
  1541.             for (staggerFromWindow = FrontWindow(); staggerFromWindow;
  1542.                  staggerFromWindow = (WindowPtr)((WindowPeek)staggerFromWindow)->nextWindow) {
  1543.                 if (!((WindowPeek)staggerFromWindow)->visible) continue;
  1544.                     /* This window is invisible.  Staggering from an invisible
  1545.                     ** window is going to confuse the user, so don't do it. */
  1546.  
  1547.                 testRct1 = GetWindowDeviceRect(staggerFromWindow);
  1548.                 testRct2 = GetRectDeviceRect(deviceRect);
  1549.                 if (!EqualRect(&testRct1, &testRct2)) continue;
  1550.                     /* This window doesn't belong to the device we are trying to
  1551.                     ** stagger on, so skip it and go to the next window. */
  1552.  
  1553.                 staggerFromRect = GetWindowStructureRect(staggerFromWindow);
  1554.                 delta.v = staggerFromRect.top  - newWindowRect.top;
  1555.                 delta.h = staggerFromRect.left - newWindowRect.left;
  1556.                 if ((absdelta.v = delta.v) < 0)
  1557.                     absdelta.v = -delta.v;
  1558.                 if ((absdelta.h = delta.h) < 0)
  1559.                     absdelta.h = -delta.h;
  1560.                 if ((absdelta.h + absdelta.v) < diamondSize) {
  1561.                     if ((delta.h + delta.v) > 0)
  1562.                         OffsetRect(&newWindowRect, delta.h, delta.v);
  1563.                             /* If the window that took our slot is closer to
  1564.                             ** the lower-right corner than we are, then use
  1565.                             ** this window's location as the basis for the
  1566.                             ** slots from now on.  This will align new windows
  1567.                             ** with previous windows that are not gridded to
  1568.                             ** the default slot positions.  The check for > 0
  1569.                             ** is necessary to prevent bouncing between two
  1570.                             ** existing windows.  This check guarantees that
  1571.                             ** we are progressing with the evaluation. */
  1572.                     break;
  1573.                         /* Break because this slot is already used. */
  1574.                 }
  1575.             }
  1576.  
  1577.             if (!staggerFromWindow) break;
  1578.                 /* If the window pointer is nil, then we tried all the windows
  1579.                 ** and none of them occupied this slot.  This means that the
  1580.                 ** slot is available for the new window. */
  1581.  
  1582.                 OffsetRect(&newWindowRect, kStaggerH, kStaggerV);
  1583.                 /* Since this slot was taken, try the next slot and go through
  1584.                 ** the window list again. */
  1585.         }
  1586.  
  1587.         if (contained) break;
  1588.         newWindowRect = slot1;
  1589.         if (!tryNum) {
  1590.             if (!vertTry) break;        /* Nothing works.  No spots at all. */
  1591.             vertTry = false;            /* Try across for the next pass. */
  1592.             diagNum = 0;
  1593.         }
  1594.         ++diagNum;
  1595.         if (vertTry)
  1596.             OffsetRect(&newWindowRect, 0, diagNum * kStaggerV);
  1597.         else
  1598.             OffsetRect(&newWindowRect, diagNum * kStaggerH, 0);
  1599.     }
  1600.  
  1601.     OffsetRect(&contentRect, newWindowRect.left - oldWindowRect.left,
  1602.                             newWindowRect.top  - oldWindowRect.top);
  1603.         /* Calculate the new content rect. */
  1604.  
  1605.     MoveWindow(window, contentRect.left, contentRect.top, false);
  1606.         /* Move the window to the new location. */
  1607.  
  1608.     oldWindowRect = newWindowRect;
  1609.  
  1610.     if (newWindowRect.right > (deviceRect.right - 2))
  1611.         newWindowRect.right = (deviceRect.right - 2);
  1612.  
  1613.     if (newWindowRect.bottom > (deviceRect.bottom - 2))
  1614.         newWindowRect.bottom = (deviceRect.bottom - 2);
  1615.  
  1616.     h = newWindowRect.right  - oldWindowRect.right;
  1617.     v = newWindowRect.bottom - oldWindowRect.bottom;
  1618.  
  1619.     SizeWindow(window, contentRect.right  - contentRect.left + h,
  1620.                        contentRect.bottom - contentRect.top + v, false);
  1621.         /* The window may have also changed size, due to sizeInfo or not fitting on the screen. */
  1622.  
  1623.  
  1624.     return(contentRect);
  1625. }
  1626.  
  1627.  
  1628.  
  1629. /*****************************************************************************/
  1630.  
  1631.  
  1632.  
  1633. #pragma segment UtilMain
  1634. void    StandardAbout(short appNameStringID)
  1635. {
  1636.     StringHandle    apNameHndl;
  1637.     VersRecHndl        curVersion;
  1638.     Str255            apName;
  1639.     Str255            verNum = "\p????";
  1640.     Ptr                verNumLocation;
  1641.     OSErr            err;
  1642.  
  1643.     apNameHndl = (StringHandle)nil;
  1644.     if (appNameStringID != kUseRealAppName) {
  1645.         if (appNameStringID != kUseCreatorString)
  1646.             apNameHndl = GetString(appNameStringID);
  1647.         if (!apNameHndl)
  1648.             apNameHndl = (StringHandle) GetAppResource(gSignature, 0, &err);
  1649.     }
  1650.  
  1651.     if ((!apNameHndl) || (appNameStringID == kUseRealAppName))
  1652.         pcpy(apName, gAppName);
  1653.     else
  1654.         pcpy(apName, *apNameHndl);
  1655.  
  1656.     curVersion = (VersRecHndl) GetAppResource('vers', 1, &err);
  1657.     if (curVersion) {
  1658.         verNumLocation = (Ptr)((long)(*curVersion)->shortVersion +
  1659.                          (long)*(*curVersion)->shortVersion + 1);
  1660.         pcpy(verNum, (StringPtr)verNumLocation);
  1661.     }
  1662.  
  1663.     ParamText(apName, verNum, "\p", "\p");
  1664.  
  1665.     CenteredAlert(rStdAboutAlert, nil, nil);
  1666. }
  1667.  
  1668.  
  1669.  
  1670. /*****************************************************************************/
  1671.  
  1672.  
  1673.  
  1674. #pragma segment UtilMain
  1675. void    StandardInitialization(short callsToMoreMasters)
  1676. {
  1677.     InitToolBox();
  1678.  
  1679.     while (callsToMoreMasters--) MoreMasters();
  1680.  
  1681.     PullApplicationToFront();
  1682.     GetSystemInfo();
  1683. }
  1684.  
  1685.  
  1686.  
  1687. /*****************************************************************************/
  1688.  
  1689.  
  1690.  
  1691. #pragma segment UtilMain
  1692. void    StandardMenuSetup(short mbarID, short appleMenuID)
  1693. {
  1694.     Handle    mbar;
  1695.     short    i, id;
  1696.  
  1697.     mbar = GetNewMBar(mbarID);                        /* Read menus into menu bar. */
  1698.     if (!mbar) return;                                /* Maybe we're faceless, so we're done. */
  1699.  
  1700.     SetMenuBar(mbar);                                /* Install menus. */
  1701.     DisposHandle(mbar);
  1702.     AddResMenu(GetMHandle(appleMenuID), 'DRVR');    /* Add DA names to Apple menu. */
  1703.  
  1704.     mbar = GetResource('MBAR', mbarID);
  1705.     for (i = **(short **)mbar; i; --i) {
  1706.         mbar = GetResource('MBAR', mbarID);            /* Make sure it's in memory for dereference. */
  1707.         id   = (*(short **)mbar)[i];
  1708.         InsertHierMenus(GetMHandle(id));
  1709.     }
  1710.  
  1711.     DrawMenuBar();
  1712. }
  1713.  
  1714.  
  1715.  
  1716. /*****************************************************************************/
  1717.  
  1718.  
  1719.  
  1720. #pragma segment UtilMain
  1721. void    InsertHierMenus(MenuHandle menu)
  1722. {
  1723.     short        item, cmd, mark;
  1724.     MenuHandle    hier;
  1725.  
  1726.     for (item = CountMItems(menu); item; --item) {
  1727.         GetItemCmd(menu, item, &cmd);
  1728.         if (cmd == 0x1B) {
  1729.             GetItemMark(menu, item, &mark);
  1730.             if (hier = GetMenu(mark)) {
  1731.                 InsertMenu(hier, -1);
  1732.                 InsertHierMenus(hier);
  1733.             }
  1734.         }
  1735.     }
  1736. }
  1737.  
  1738.  
  1739.  
  1740. /*****************************************************************************/
  1741.  
  1742.  
  1743.  
  1744. /* Check to see if a given trap is implemented. */
  1745.  
  1746. #pragma segment UtilMain
  1747. Boolean TrapExists(short theTrap)
  1748. {
  1749.     TrapType    theTrapType;
  1750.  
  1751.     theTrapType = GetTrapType(theTrap);
  1752.     if ((theTrapType == ToolTrap) && ((theTrap &= 0x07FF) >= NumToolboxTraps()))
  1753.         theTrap = _Unimplemented;
  1754.  
  1755.     return(NGetTrapAddress(_Unimplemented, ToolTrap) != NGetTrapAddress(theTrap, theTrapType));
  1756. }
  1757.  
  1758.  
  1759.  
  1760. /*****************************************************************************/
  1761.  
  1762.  
  1763.  
  1764. /* Zoom the window to the size appropriate for the device that contains the
  1765. ** most of the window.  An additional feature is that you can state the
  1766. ** maximum that a window should be zoomed, either horizontally or vertically.
  1767. ** If you pass in a maximum of 0 for the zoom for either direction, then that
  1768. ** direction will be zoomed to fit the device. */
  1769.  
  1770. #pragma segment UtilMain
  1771. void    ZoomToWindowDevice(WindowPtr window, short maxWidth, short maxHeight,
  1772.                            short zoomDir, Boolean front)
  1773. {
  1774.      GrafPtr    oldPort;
  1775.     Rect    contentRect, structureRect, deviceRect, newRect;
  1776.     short    width, height, dx, dy;
  1777.  
  1778.     GetPort(&oldPort);
  1779.     SetPort(window);
  1780.     EraseRect(&window->portRect);         /* Recommended for cosmetic reasons. */
  1781.  
  1782.     /* If there is the possibility of multiple gDevices, then we must check them to
  1783.     ** make sure we are zooming onto the right display device when zooming out. */
  1784.  
  1785.     if (zoomDir == inZoomOut) {
  1786.  
  1787.         contentRect      = GetWindowContentRect(window);
  1788.         structureRect = GetWindowStructureRect(window);
  1789.         deviceRect      = GetWindowDeviceRectNMB(window);
  1790.  
  1791.         deviceRect.left   += (contentRect.left - structureRect.left + 2);
  1792.         deviceRect.top    += (contentRect.top - structureRect.top + 2);
  1793.         deviceRect.right  -= (structureRect.right - contentRect.right + 1);
  1794.         deviceRect.bottom -= (structureRect.bottom - contentRect.bottom + 1);
  1795.         newRect = deviceRect;
  1796.  
  1797.         if (maxWidth)
  1798.             if ((width = deviceRect.right - deviceRect.left) > maxWidth)
  1799.                 newRect.right = (newRect.left = contentRect.left) + maxWidth;
  1800.         if (maxHeight)
  1801.             if ((height = deviceRect.bottom - deviceRect.top) > maxHeight)
  1802.                 newRect.bottom = (newRect.top = contentRect.top) + maxHeight;
  1803.         if ((dx = deviceRect.left - newRect.left) < 0)
  1804.             if ((dx = deviceRect.right - newRect.right) > 0)
  1805.                 dx = 0;
  1806.         if ((dy = deviceRect.top - newRect.top) < 0)
  1807.             if ((dy = deviceRect.bottom - newRect.bottom) > 0)
  1808.                 dy = 0;
  1809.         OffsetRect(&newRect, dx, dy);
  1810.  
  1811.         (*(WStateDataHandle)(((WindowPeek)window)->dataHandle))->stdState = newRect;
  1812.             /* Set up the WStateData record for this window. */
  1813.     }
  1814.  
  1815.     ZoomWindow(window, zoomDir, front);
  1816.     SetPort(oldPort);
  1817. }
  1818.  
  1819.  
  1820.  
  1821. /*****************************************************************************/
  1822. /*****************************************************************************/
  1823. /*****************************************************************************/
  1824.  
  1825.  
  1826.  
  1827. #pragma segment UtilMain
  1828. void    DoDrawGrowIcon(WindowPtr window, Boolean horLine, Boolean verLine)
  1829. {
  1830.     WindowPtr    oldPort;
  1831.     Rect        rct;
  1832.     RgnHandle    oldClip, newClip;
  1833.  
  1834.     GetPort(&oldPort);
  1835.     SetPort(window);
  1836.  
  1837.     rct = window->portRect;
  1838.     rct.left = rct.right  - 15;
  1839.     rct.top  = rct.bottom - 15;
  1840.  
  1841.     if (!((WindowPeek)window)->hilited) {
  1842.         FrameRect(&rct);
  1843.         ++rct.top;
  1844.         ++rct.left;
  1845.         EraseRect(&rct);
  1846.         SetPort(oldPort);
  1847.         return;
  1848.     }
  1849.  
  1850.     oldClip = NewRgn();
  1851.     newClip = NewRgn();
  1852.  
  1853.     if (horLine)
  1854.         rct.left = window->portRect.left;
  1855.     if (verLine)
  1856.         rct.top  = window->portRect.top;
  1857.     RectRgn(newClip, &rct);
  1858.  
  1859.     GetClip(oldClip);
  1860.     SetClip(newClip);
  1861.     DrawGrowIcon(window);        /* Draw grow icon without scrollbar lines. */
  1862.  
  1863.     SetClip(oldClip);
  1864.     DisposeRgn(oldClip);
  1865.     DisposeRgn(newClip);
  1866.  
  1867.     SetPort(oldPort);
  1868. }
  1869.  
  1870.  
  1871.  
  1872. /*****************************************************************************/
  1873.  
  1874.  
  1875.  
  1876. /* This is used to "intelligently" insert a menu item into a menu.  Pass it
  1877. ** the menu to be modified, the text of the item being added, plus where the
  1878. ** item is to be inserted.  The location to be inserted is described by two
  1879. ** parameters:  section & where.
  1880. **
  1881. ** section:  Indicates which group of menu items you wish to add an item to.
  1882. **           Menu item section 1 is all of the items before the first
  1883. **           dividing line.  Menu item section 2 is all items after the
  1884. **           first dividing line and before the second, and so on.  If you
  1885. **           have no dividing lines, you have just 1 section so pass in 1.
  1886. **
  1887. ** where:    Indicates the item position relative to the section.  To add an
  1888. **           item such that it is the first item in a section, pass in a 1.
  1889. **           It will be added in front of the first item in the section.
  1890. **
  1891. **           NOTE:  You should never pass in a section or where parameter of 0.
  1892. **
  1893. ** Negative values for "where" are magic.  If where = kMenuItemTxtInsert, then
  1894. ** it inserts the item alphabetically into the section.  A where of
  1895. ** kMenuItemNumInsert works the same as kMenuItemTxtInsert, except it treats
  1896. ** the strings are numbers for comparison purposes.  If you want to add the
  1897. ** item to the end of a section, use kMenuItemSectionEnd.
  1898. **
  1899. ** As a final goodie, SmartInsMenuItem returns the menu item # from the
  1900. ** beginning of the menu, not section.
  1901. */
  1902.  
  1903. #pragma segment UtilMain
  1904. short    SmartInsMenuItem(MenuHandle theMenu, StringPtr theText, short section, short where)
  1905. {
  1906.     short    numItems, base, i;
  1907.     short    insertType, val;
  1908.     Str255    cmpTxt, txt;
  1909.  
  1910.     numItems = CountMItems(theMenu);    /* Total number of items in menu. */
  1911.  
  1912.     if (--section < 0)
  1913.         section = 0;                    /* We want section 0-based. */
  1914.  
  1915.     for (base = 0, i = 1; (section) && (i <= numItems); ++i) {
  1916.         GetItem(theMenu, base + i, txt);
  1917.         if (txt[1] == '-') {
  1918.             base = i;
  1919.             --section;
  1920.         }
  1921.     }        /* base now tells us our section starting offset. */
  1922.  
  1923.     if (where < 0) {        /* If magic mode... */
  1924.  
  1925.         InsMenuItem(theMenu, theText, 0);        /* Take out meta characters */
  1926.         GetItem(theMenu, 1, cmpTxt);            /* for comparison purposes. */
  1927.         DelMenuItem(theMenu, 1);
  1928.  
  1929.         insertType = where;
  1930.         val = p2num(cmpTxt, 10, nil);
  1931.  
  1932.         for (where = 1; i <= (numItems - base); ++where) {
  1933.             GetItem(theMenu, where + base, txt);
  1934.             if (txt[1] == '-') break;
  1935.             if ((insertType == kMenuItemTxtInsert) && ((IUCompString(cmpTxt, txt) < 0))) break;
  1936.             if ((insertType == kMenuItemNumInsert) && (val < p2num(txt, 10, nil)))       break;
  1937.         }
  1938.     }
  1939.  
  1940.     where += base;
  1941.     InsMenuItem(theMenu, theText, where - 1);        /* InsMenuItem does an insert-after. */
  1942.  
  1943.     return(where);
  1944. }
  1945.  
  1946.  
  1947.  
  1948. /*****************************************************************************/
  1949.  
  1950.  
  1951.  
  1952. #pragma segment UtilMain
  1953. short    CountMSections(MenuHandle theMenu)
  1954. {
  1955.     short    numItems, numSections, i;
  1956.     Str255    txt;
  1957.  
  1958.     numItems = CountMItems(theMenu);    /* Total number of items in menu. */
  1959.  
  1960.     for (numSections = i = 1; i <= numItems; ++i) {
  1961.         GetItem(theMenu, i, txt);
  1962.         if (txt[1] == '-')
  1963.             ++numSections;
  1964.     }
  1965.  
  1966.     return(numSections);
  1967. }
  1968.  
  1969.  
  1970.  
  1971. /*****************************************************************************/
  1972.  
  1973.  
  1974.  
  1975. #pragma segment UtilMain
  1976. short    FindMenuItem(MenuHandle theMenu, StringPtr cmpTxt)
  1977. {
  1978.     short    item;
  1979.     Str255    txt;
  1980.  
  1981.     for (item = CountMItems(theMenu); item; --item) {
  1982.         GetItem(theMenu, item, txt);
  1983.         if (!IUCompString(cmpTxt, txt)) break;
  1984.     }
  1985.  
  1986.     return(item);
  1987. }
  1988.  
  1989.  
  1990.  
  1991. /*****************************************************************************/
  1992.  
  1993.  
  1994.  
  1995. #pragma segment UtilMain
  1996. OSErr    PersistFSSpec(PFSSpecPtr pfss)
  1997. {
  1998.     OSErr            err;
  1999.     HParamBlockRec    pb;
  2000.     char            delim;
  2001.  
  2002.     memset(&pb, 0, sizeof(HParamBlockRec));        /* Make us a happy ParamBlock. */
  2003.     pb.volumeParam.ioNamePtr = pfss->volName;
  2004.  
  2005.     if (!(pfss->fss.name[0])) {                /* If no file name, then there's no file. */
  2006.         pfss->volName[0] = 0;                /* Zap all remnants of file specification. */
  2007.         pfss->fss.vRefNum = 0;
  2008.         return(noErr);
  2009.     }
  2010.  
  2011.     if (pb.volumeParam.ioVRefNum = pfss->fss.vRefNum) {
  2012.         pfss->volName[0] = 0;    /* If we are passed in a vRefNum, then we are
  2013.                                 ** wanting the volume name.  This is what we are
  2014.                                 ** looking to get, so show it as currently missing. */
  2015.         err = PBHGetVInfo(&pb, false);
  2016.     }
  2017.     else {
  2018.         if (!(pfss->volName[0])) return(noErr);
  2019.  
  2020.         pb.volumeParam.ioVolIndex = -1;        /* Use the name to find the vRefNum. */
  2021.         delim = (gAUXVersion) ? '/' : ':';
  2022.         if (pfss->volName[pfss->volName[0]] != delim)
  2023.             pfss->volName[++(pfss->volName[0])] = delim;
  2024.                 /* Make sure that volume name ends with a delimiter. */
  2025.  
  2026.         if (!(err = PBHGetVInfo(&pb, false)))
  2027.             pfss->fss.vRefNum = pb.volumeParam.ioVRefNum;
  2028.     }
  2029.  
  2030.     return(err);
  2031. }
  2032.  
  2033.  
  2034.  
  2035. /*****************************************************************************/
  2036.  
  2037.  
  2038.  
  2039. #pragma segment UtilMain
  2040. StringPtr    PathNameFromDirID(long dirID, short vRefNum, StringPtr str)
  2041. {
  2042.     CInfoPBRec    block;
  2043.     Str255        directoryName;
  2044.  
  2045.     *str = 0;
  2046.     block.dirInfo.ioNamePtr = directoryName;
  2047.     block.dirInfo.ioDrParID = dirID;
  2048.  
  2049.     do {
  2050.         block.dirInfo.ioVRefNum   = vRefNum;
  2051.         block.dirInfo.ioFDirIndex = -1;
  2052.         block.dirInfo.ioDrDirID   = block.dirInfo.ioDrParID;
  2053.  
  2054.         if (PBGetCatInfo(&block, false)) {
  2055.             *str = 0;
  2056.             break;
  2057.         }
  2058.  
  2059.         if (gAUXVersion) {
  2060.             if (directoryName[1] != '/')
  2061.                 pcat(directoryName, "\p/");
  2062.                     /* If this isn't root (i.e. '/'), append a slash ('/'). */
  2063.         } else pcat(directoryName, "\p:");
  2064.             /* Append a Macintosh style colon (':'). */
  2065.  
  2066.         pcat(directoryName, str);
  2067.         pcpy(str, directoryName);
  2068.  
  2069.     } while (block.dirInfo.ioDrDirID != fsRtDirID);
  2070.  
  2071.     return(str);
  2072. }
  2073.  
  2074.  
  2075.  
  2076. /*****************************************************************************/
  2077.  
  2078.  
  2079.  
  2080. #pragma segment UtilMain
  2081. void    InitQuickTime(void)
  2082. {
  2083.     ComponentDescription    controllerDescriptor;
  2084.  
  2085.     if (!gQTVersion) {
  2086.         if (!(Gestalt(gestaltQuickTime, &gQTVersion))) {
  2087.             if (EnterMovies())
  2088.                 gQTVersion = 0;
  2089.             else {
  2090.                 controllerDescriptor.componentType         = 'play';
  2091.                 controllerDescriptor.componentSubType      = 0;
  2092.                 controllerDescriptor.componentManufacturer = 0;
  2093.                 controllerDescriptor.componentFlags        = 0;
  2094.                 controllerDescriptor.componentFlagsMask    = 0;
  2095.                 gMovieControllerComponent = FindNextComponent((Component)0, &controllerDescriptor);
  2096.             }
  2097.         }
  2098.     }
  2099. }
  2100.  
  2101.  
  2102.  
  2103. /*****************************************************************************/
  2104. /*****************************************************************************/
  2105. /*****************************************************************************/
  2106.  
  2107.  
  2108.  
  2109. #pragma segment Controls
  2110. pascal Boolean    AlertFilter(DialogPtr dlg, EventRecord *event, short *item)
  2111. {
  2112.     short    what, theChr, theMod, handled;
  2113.  
  2114.     what = event->what;
  2115.     if (event->what == keyDown) {
  2116.         theChr = event->message   & charCodeMask;
  2117.         theMod = event->modifiers & keyCodeMask;
  2118.         if ((theChr != 0x0D) && (theChr != 0x03))
  2119.             event->what = nullEvent;
  2120.         if (theMod & (cmdKey + optionKey + controlKey))
  2121.             event->what = nullEvent;
  2122.     }
  2123.     handled = KeyEquivFilter(dlg, event, item);
  2124.     event->what = what;
  2125.     return(handled);
  2126. }
  2127.  
  2128.  
  2129.  
  2130. /*****************************************************************************/
  2131.  
  2132.  
  2133.  
  2134. /* This code expects the key equivalents to be in item #2, which is a StatText
  2135. ** item that is located so the text is outside of the dialog.  This allows us
  2136. ** to put key equivalent information in the resource fork, so the key
  2137. ** equivalents are localizable.
  2138. **
  2139. ** An example save changes before closing or quitting res source with
  2140. ** keyEquiv info would look like:
  2141. **
  2142. ** resource 'DITL' (rYesNoCancel, purgeable) {
  2143. **     {
  2144. **         {71, 315, 91, 367}, Button     { enabled, "Save" },
  2145. **         {0, -1000, 20, 2},  StaticText { disabled,
  2146. **             "=S190001,=s190001,=D190003,=d190003,=.190104,1B190004" },
  2147. **         {71, 80, 91, 162},  Button { enabled, "Don’t Save" },
  2148. **         {71, 244, 91, 302}, Button { enabled, "Cancel" },
  2149. **         {11, 78, 61, 366},  StaticText { disabled,
  2150. **             "Save changes to the document “^0” before ^1?" },
  2151. **         {11, 23, 43, 55},        Icon { disabled, 2 }
  2152. **     }
  2153. ** };
  2154. **
  2155. ** The document name would be the string for param #0.
  2156. ** The text "closing" or "quitting" would be the string for param #1.
  2157. **
  2158. ** The keyEquiv entry is item #2, which has a rect that pushes it out of the
  2159. ** dialog.  The string info is interpreted as to what the key/modifier combo
  2160. ** is, and what dialog item it relates to.
  2161. **
  2162. ** A single key equiv entry is 8 characters.  Entries are separated by commas.
  2163. **
  2164. ** If the first character of an entry is an =, then the next character is the
  2165. ** key.  If the first character isn't an =, then the first two characters are
  2166. ** the hex value of the key.  (Ex:  =S or =s for save, 1B for ESC.)
  2167. **
  2168. ** If the key pressed is the same as the key value for any of the entries, then
  2169. ** the next two characters are the hex value for which modifiers to test.  This
  2170. ** modifier test value is anded with the modifier.  The result is then compared
  2171. ** to the value of the next two hex digits.  If they are equal, then the
  2172. ** modifiers are correct, as well as the key.  If this is so, we have a winner.
  2173. **
  2174. ** "=S190001,=s190001,=D190003,=d190003,=.190104,1B190004"
  2175. **
  2176. ** The above string breaks down as follows:
  2177. ** =S190001  =S  if event keypress is an S, check the modifier values
  2178. **           19  check controlKey/optionKey/cmdKey
  2179. **           00  all modifiers we are testing for should be false
  2180. **           01  if above is true, keypress maps to item # 1
  2181. ** =s190001  Same as =S, but lowercase
  2182. ** =D190001  Same as =S, but maps to item #3
  2183. ** =d190001  Same as =D, but lowercase
  2184. ** =.190104  =.  if event keypress is a period, check the modifier values
  2185. **           19  check controlKey/optionKey/cmdKey
  2186. **           01  controlKey/optionKey should be false, cmdKey should be true
  2187. **           04  if above is true, keypress maps to item # 4
  2188. ** 1B190004  1B  if event keypress is an ESC, check the modifier values
  2189. **           19  check controlKey/optionKey/cmdKey
  2190. **           00  all modifiers we are testing for should be false
  2191. **           04  if above is true, keypress maps to item # 4
  2192. */
  2193.  
  2194. #pragma segment Controls
  2195. pascal Boolean    KeyEquivFilter(DialogPtr dlg, EventRecord *event, short *item)
  2196. {
  2197.     short    itemType;
  2198.     Handle    itemHndl;
  2199.     Rect    itemRect;
  2200.     Str255    itemText;
  2201.     short    i, theChr, cc, theMod, equivChr, modMask, modVal, itemNum;
  2202.  
  2203.     if (event->what == updateEvt) {
  2204.         if (dlg == (DialogPtr)event->message)
  2205.             OutlineDialogItem(dlg, 1);
  2206.         return(false);
  2207.     }
  2208.  
  2209.     if (event->what != keyDown) return(false);
  2210.  
  2211.     itemNum = 0;
  2212.  
  2213.     theChr = event->message   & charCodeMask;
  2214.     theMod = event->modifiers & keyCodeMask;
  2215.  
  2216.     if ((theChr == 0x0D) || (theChr == 0x03)) {        /* If return or enter... */
  2217.         if (!(theMod & (cmdKey + optionKey + controlKey))) {
  2218.             *item = 1;
  2219.             return(true);
  2220.         }
  2221.     }
  2222.  
  2223.     GetDItem(dlg, 2, &itemType, &itemHndl, &itemRect);
  2224.     if (itemHndl) {
  2225.         GetIText(itemHndl, itemText);
  2226.         for (i = 1; i <= *itemText; i += 9) {
  2227.             cc = theChr;
  2228.             if (itemText[i] == (unsigned char)'≈')
  2229.                 if ((cc >= 'a') && (cc <= 'z')) cc -= 32;
  2230.             equivChr = GetHexByte((char *)(itemText + i));
  2231.             modMask  = GetHexByte((char *)(itemText + i + 2)) << 8;
  2232.             modVal   = GetHexByte((char *)(itemText + i + 4)) << 8;
  2233.             itemNum  = GetHexByte((char *)(itemText + i + 6));
  2234.             if (cc == equivChr)
  2235.                 if ((theMod & modMask) == modVal) break;
  2236.             itemNum = 0;
  2237.         }
  2238.     }
  2239.  
  2240.     if (itemNum) {
  2241.         GetDItem(dlg, itemNum, &itemType, &itemHndl, &itemRect);
  2242.         SelectButton((ControlHandle)itemHndl);
  2243.         *item = itemNum;
  2244.         return(true);
  2245.     }
  2246.  
  2247.     return(false);
  2248. }
  2249.  
  2250.  
  2251.  
  2252. /*****************************************************************************/
  2253. /*****************************************************************************/
  2254. /*****************************************************************************/
  2255.  
  2256.  
  2257.  
  2258. /* This function returns which kind of button the control is.  This does more
  2259. ** than GetCVariant in that it makes sure that the control is actually a
  2260. ** button.  It does this by comparing the defProc against the known defProc
  2261. ** for the various button types.  For 7.0, there is only one defProc for all
  2262. ** variants, but for pre-7.0, there is one defProc value for each variant.
  2263. ** The method below handles either case. */
  2264.  
  2265. #pragma segment Controls
  2266. short    GetButtonVariant(ControlHandle ctl)
  2267. {
  2268.     short            i;
  2269.     Rect            dummy;
  2270.     ControlHandle    dummyCtl;
  2271.  
  2272.     for (i = pushButProc; i <= radioButProc + useWFont; ++i) {
  2273.         if (i == radioButProc + 1)
  2274.             i = pushButProc + useWFont;
  2275.         if (!gButtonProcs[i]) {
  2276.             SetRect(&dummy, 0, 0, 0, 0);
  2277.             dummyCtl = NewControl((*ctl)->contrlOwner, &dummy, (ConstStr255Param)"\p",
  2278.                                   false, 1, 0, 1, i, 0L);
  2279.             if (dummyCtl) {
  2280.                 gButtonProcs[i] = (*dummyCtl)->contrlDefProc;
  2281.                 DisposeControl(dummyCtl);
  2282.             }
  2283.         }
  2284.         if (*(*ctl)->contrlDefProc == *gButtonProcs[i])
  2285.             return(GetCVariant(ctl) & (0xFFFF - useWFont));
  2286.                 /* The handle may be locked, which means that the hi-bit
  2287.                 ** may be on, thus invalidating the compare.  Dereference the
  2288.                 ** handles to get rid of this possibility. */
  2289.     }
  2290.  
  2291.     return(-1);
  2292. }
  2293.  
  2294.  
  2295.  
  2296. /*****************************************************************************/
  2297.  
  2298.  
  2299.  
  2300. #pragma segment Controls
  2301. Boolean GetCheckOrRadio(DialogPtr dlgPtr, short itemNo)
  2302. {
  2303.     short    iKind;
  2304.     Handle    iHandle;
  2305.     Rect    iRect;
  2306.  
  2307.     GetDItem(dlgPtr, itemNo, &iKind, &iHandle, &iRect);
  2308.     return(GetCtlValue((ControlHandle)iHandle) != 0);
  2309. }
  2310.  
  2311.  
  2312.  
  2313. /*****************************************************************************/
  2314.  
  2315.  
  2316.  
  2317. #pragma segment Controls
  2318. Boolean    IsScrollBar(ControlHandle ctl)
  2319. {
  2320.     Rect            dummy;
  2321.     ControlHandle    dummyCtl;
  2322.  
  2323.     if (!ctl) return(false);
  2324.  
  2325.     if (!gScrollProc) {
  2326.         SetRect(&dummy, 0, 0, 16, 100);
  2327.         dummyCtl = NewControl((*ctl)->contrlOwner, &dummy, (ConstStr255Param)"\p",
  2328.                               false, 1, 0, 1, scrollBarProc, 0L);
  2329.         if (dummyCtl) {
  2330.             gScrollProc = (*dummyCtl)->contrlDefProc;
  2331.             DisposeControl(dummyCtl);
  2332.         }
  2333.     }
  2334.  
  2335.     return((*(*ctl)->contrlDefProc) == (*gScrollProc));
  2336.         /* The handle may be locked, which means that the hi-bit
  2337.         ** may be on, thus invalidating the compare.  Dereference the
  2338.         ** handles to get rid of this possibility. */
  2339. }
  2340.  
  2341.  
  2342.  
  2343. /*****************************************************************************/
  2344.  
  2345.  
  2346.  
  2347. #pragma segment Controls
  2348. void    MoveStyledControl(ControlHandle ctl, short xloc, short yloc)
  2349. {
  2350.     char    vv, hh;
  2351.  
  2352.     if (GetCtlValue(ctl)) {
  2353.         if (GetButtonVariant(ctl) == pushButProc) {
  2354.             hh = (*ctl)->contrlHilite;
  2355.             (*ctl)->contrlHilite = 1;        /* Force outline off. */
  2356.             OutlineControl(ctl);
  2357.             (*ctl)->contrlHilite = hh;
  2358.         }
  2359.     }
  2360.  
  2361.     vv = (*ctl)->contrlVis;
  2362.     HideControl(ctl);
  2363.     MoveControl(ctl, xloc, yloc);
  2364.     (*ctl)->contrlVis = vv;
  2365.  
  2366.     DoDraw1Control(ctl, false);
  2367. }
  2368.  
  2369.  
  2370.  
  2371. /*****************************************************************************/
  2372.  
  2373.  
  2374.  
  2375. #pragma segment Controls
  2376. void    SizeStyledControl(ControlHandle ctl, short xsize, short ysize)
  2377. {
  2378.     char    vv, hh;
  2379.  
  2380.     if (GetCtlValue(ctl)) {
  2381.         if (GetButtonVariant(ctl) == pushButProc) {
  2382.             hh = (*ctl)->contrlHilite;
  2383.             (*ctl)->contrlHilite = 1;        /* Force outline off. */
  2384.             OutlineControl(ctl);
  2385.             (*ctl)->contrlHilite = hh;
  2386.         }
  2387.     }
  2388.  
  2389.     vv = (*ctl)->contrlVis;
  2390.     HideControl(ctl);
  2391.     SizeControl(ctl, xsize, ysize);
  2392.     (*ctl)->contrlVis = vv;
  2393.  
  2394.     DoDraw1Control(ctl, false);
  2395. }
  2396.  
  2397.  
  2398.  
  2399. /*****************************************************************************/
  2400.  
  2401.  
  2402.  
  2403. #pragma segment Controls
  2404. void    SetStyledCtlValue(ControlHandle ctl, short value)
  2405. {
  2406.     char    hh;
  2407.  
  2408.     UseControlStyle(ctl);
  2409.     SetCtlValue(ctl, value);
  2410.     UseControlStyle(nil);
  2411.  
  2412.     if (GetButtonVariant(ctl) == pushButProc) {
  2413.         if (!value) {
  2414.             hh = (*ctl)->contrlHilite;
  2415.             (*ctl)->contrlHilite = 1;        /* Force outline off. */
  2416.             OutlineControl(ctl);
  2417.             (*ctl)->contrlHilite = hh;
  2418.         }
  2419.         else
  2420.             OutlineControl(ctl);
  2421.     }
  2422. }
  2423.  
  2424.  
  2425.  
  2426. /*****************************************************************************/
  2427.  
  2428.  
  2429.  
  2430. #pragma segment Controls
  2431. void    ShowStyledControl(ControlHandle ctl)
  2432. {
  2433.     if (!(*ctl)->contrlVis) {
  2434.         (*ctl)->contrlVis = 255;
  2435.         DoDraw1Control(ctl, false);
  2436.     }
  2437. }
  2438.  
  2439.  
  2440.  
  2441. /*****************************************************************************/
  2442.  
  2443.  
  2444.  
  2445. #pragma segment Controls
  2446. void    HideStyledControl(ControlHandle ctl)
  2447. {
  2448.     char    hh;
  2449.  
  2450.     if (GetButtonVariant(ctl) == pushButProc) {
  2451.         if ((*ctl)->contrlValue) {
  2452.             hh = (*ctl)->contrlHilite;
  2453.             (*ctl)->contrlHilite = 1;        /* Force outline off. */
  2454.             OutlineControl(ctl);
  2455.             (*ctl)->contrlHilite = hh;
  2456.         }
  2457.     }
  2458.     HideControl(ctl);
  2459. }
  2460.  
  2461.  
  2462.  
  2463. /*****************************************************************************/
  2464.  
  2465.  
  2466.  
  2467. #pragma segment Controls
  2468. void    OffsetControl(ControlHandle ctl, short dx, short dy)
  2469. {
  2470.     Rect    ctlRect;
  2471.  
  2472.     ctlRect = (*ctl)->contrlRect;
  2473.     MoveStyledControl(ctl, ctlRect.left + dx, ctlRect.top + dy);
  2474. }
  2475.  
  2476.  
  2477.  
  2478. /*****************************************************************************/
  2479.  
  2480.  
  2481.  
  2482. /* Given any control handle, this will draw an outline around it.  This is used
  2483. ** for the default button of a window.  The extra nice feature here is that
  2484. ** I’ll erase the outline for buttons that are inactive.  Seems like there
  2485. ** should be a Toolbox call for getting a control’s hilite state.  Since there
  2486. ** isn’t, I have to look into the control record myself.  This should be called
  2487. ** for update and activate events.
  2488. **
  2489. ** The method for determining the oval diameters for the roundrect is a little
  2490. ** different than that recommended by Inside Mac. IM I-407 suggests that you
  2491. ** use a hardcoded (16,16) for the diameters.  However, this only looks good
  2492. ** for small roundrects.  For larger ones, the outline doesn’t follow the inner
  2493. ** roundrect because the CDEF for simple buttons doesn’t use (16,16).  Instead,
  2494. ** it uses half the height of the button as the diameter.  By using this
  2495. ** formula, too, our outlines look better. */
  2496.  
  2497. #pragma segment Controls
  2498. void    OutlineControl(ControlHandle button)
  2499. {
  2500.     WindowPtr    oldPort;
  2501.     Rect        theRect;
  2502.     PenState    curPen;
  2503.     short        buttonOval;
  2504.  
  2505.     if (button) {
  2506.         if ((*button)->contrlVis) {
  2507.             GetPort(&oldPort);
  2508.             SetPort((*button)->contrlOwner);
  2509.             GetPenState(&curPen);
  2510.             PenNormal();
  2511.             theRect = (*button)->contrlRect;
  2512.             InsetRect(&theRect, kButtonFrameInset, kButtonFrameInset);
  2513.             buttonOval = (theRect.bottom - theRect.top) / 2 + 2;
  2514.  
  2515.             switch ((*button)->contrlHilite) {
  2516.                 case kCntlActivate:
  2517.                     PenPat((ConstPatternParam)&QD(black));
  2518.                     break;
  2519.                 case kCntlDeactivate:
  2520.                     PenPat((ConstPatternParam)&QD(gray));
  2521.                     break;
  2522.                 default:
  2523.                     PenPat((ConstPatternParam)&QD(white));
  2524.                     break;
  2525.             }
  2526.             PenSize(kButtonFrameSize, kButtonFrameSize);
  2527.             FrameRoundRect(&theRect, buttonOval, buttonOval);
  2528.             SetPenState(&curPen);
  2529.             SetPort(oldPort);
  2530.         }
  2531.     }
  2532. }
  2533.  
  2534.  
  2535.  
  2536. /*****************************************************************************/
  2537.  
  2538.  
  2539.  
  2540. #pragma segment Controls
  2541. void    OutlineDialogItem(DialogPtr dlgPtr, short item)
  2542. {
  2543.     short    iKind;
  2544.     Handle    iHandle;
  2545.     Rect    iRect;
  2546.  
  2547.     GetDItem(dlgPtr, item, &iKind, &iHandle, &iRect);
  2548.     OutlineControl((ControlHandle) iHandle);
  2549. }
  2550.  
  2551.  
  2552.  
  2553. /*****************************************************************************/
  2554.  
  2555.  
  2556.  
  2557. /* Given the button control handle, this will cause the button to look as if it
  2558. ** has been clicked in.  This is nice to do for the user if they type return or
  2559. ** enter to select the default item. */
  2560.  
  2561. #pragma segment Controls
  2562. void    SelectButton(ControlHandle button)
  2563. {
  2564.     long    finalTicks;
  2565.  
  2566.     UseControlStyle(button);
  2567.     HiliteControl(button, kSelect);
  2568.     Delay(kDelayTime, &finalTicks);
  2569.     HiliteControl(button, kDeselect);
  2570.     UseControlStyle(nil);
  2571. }
  2572.  
  2573.  
  2574.  
  2575. /*****************************************************************************/
  2576.  
  2577.  
  2578.  
  2579. /* Handy function for setting the value of a radio button.  Given a dialog
  2580. ** pointer, and item number, and a state, this function will take care of the
  2581. ** rest. */
  2582.  
  2583. #pragma segment Controls
  2584. void    SetCheckOrRadioButton(DialogPtr dlgPtr, short itemNo, short state)
  2585. {
  2586.     short    iKind;
  2587.     Handle    iHandle;
  2588.     Rect    iRect;
  2589.  
  2590.     GetDItem(dlgPtr, itemNo, &iKind, &iHandle, &iRect);
  2591.     SetCtlValue((ControlHandle)iHandle, state);
  2592. }
  2593.  
  2594.  
  2595.  
  2596. /*****************************************************************************/
  2597.  
  2598.  
  2599.  
  2600. #pragma segment Controls
  2601. void    ToggleCheck(DialogPtr dlgPtr, short chkItem)
  2602. {
  2603.     short    iKind;
  2604.     Handle    iHandle;
  2605.     Rect    iRect;
  2606.  
  2607.     GetDItem(dlgPtr, chkItem, &iKind, &iHandle, &iRect);
  2608.     SetCtlValue((ControlHandle) iHandle, !GetCtlValue((ControlHandle)iHandle));
  2609. }
  2610.  
  2611.  
  2612.  
  2613. /*****************************************************************************/
  2614.  
  2615.  
  2616.  
  2617. #pragma segment Controls
  2618. Boolean    WhichControl(Point mouseLoc, long when, WindowPtr window, ControlHandle *ctlHit)
  2619. {
  2620.     Boolean                    found;
  2621.     Rect                    rct;
  2622.     ControlHandle            ctl, lastCtl;
  2623.     static ControlHandle    lastWhenCtl;
  2624.  
  2625.     gWhichCtlTracking = false;
  2626.  
  2627.     found   = false;
  2628.     lastCtl = nil;
  2629.  
  2630.     if (ctlHit)
  2631.         *ctlHit = nil;
  2632.  
  2633.     if (window) {
  2634.         ctl = ((WindowPeek)window)->controlList;
  2635.         while (ctl) {
  2636.             if ((*ctl)->contrlVis) {
  2637.                 rct = (*ctl)->contrlRect;
  2638.                 if (PtInRect(mouseLoc, &rct)) {
  2639.                     found = true;            /* Return the last hit in the linked list, as */
  2640.                     lastCtl = ctl;            /* it is drawn last, and therefore on top.    */
  2641.                 }
  2642.             }
  2643.             ctl = (*ctl)->nextControl;
  2644.         }
  2645.     }
  2646.  
  2647.     if (ctlHit)
  2648.         *ctlHit = lastCtl;
  2649.  
  2650.     gWhichCtlDbl = false;
  2651.     if (when) {
  2652.         gWhichCtlHit = lastWhenCtl;
  2653.         lastWhenCtl  = lastCtl;
  2654.         if (gWhichCtlHit == lastCtl)
  2655.             if (when < gWhichCtlWhen + 30)
  2656.                 gWhichCtlDbl = true;
  2657.         gWhichCtlWhen = when;
  2658.     }
  2659.     gWhichCtlHit = lastCtl;
  2660.  
  2661.     return(found);
  2662. }
  2663.  
  2664.  
  2665.  
  2666. /*****************************************************************************/
  2667.  
  2668.  
  2669.  
  2670. #pragma segment Controls
  2671. void    DoDrawControls(WindowPtr window, Boolean scrollBarsOnly)
  2672. {
  2673.     ControlHandle    ctl;
  2674.  
  2675.     ctl = ((WindowPeek)window)->controlList;
  2676.     while (ctl) {
  2677.         DoDraw1Control(ctl, scrollBarsOnly);
  2678.         ctl = (*ctl)->nextControl;
  2679.     }
  2680. }
  2681.  
  2682.  
  2683.  
  2684. /*****************************************************************************/
  2685.  
  2686.  
  2687.  
  2688. #pragma segment Controls
  2689. void    DoDraw1Control(ControlHandle ctl, Boolean scrollBarsOnly)
  2690. {
  2691.     WindowPtr    window, oldPort;
  2692.     Rect        rct, srct;
  2693.     Point        org;
  2694.  
  2695.     if (IsScrollBar(ctl)) {
  2696.         window = (*ctl)->contrlOwner;
  2697.         if (((WindowPeek)window)->hilited)
  2698.             Draw1Control(ctl);
  2699.         else {
  2700.             if ((*ctl)->contrlVis) {
  2701.                 GetPort(&oldPort);
  2702.                 SetPort(window);
  2703.                 rct = (*ctl)->contrlRect;
  2704.                 FrameRect(&rct);
  2705.                 InsetRect(&rct, 1, 1);
  2706.                 EraseRect(&rct);
  2707.                 SetPort(oldPort);
  2708.             }
  2709.         }
  2710.     }
  2711.     else {
  2712.         if (!scrollBarsOnly) {
  2713.             window = (*ctl)->contrlOwner;
  2714.             org.h = window->portRect.left;
  2715.             org.v = window->portRect.top;
  2716.             rct = (*ctl)->contrlRect;
  2717.             SectRect(&rct, &(window->portRect), &srct);
  2718.             if (!EmptyRect(&srct)) {
  2719.                 UseControlStyle(ctl);
  2720.                 Draw1Control(ctl);
  2721.                 UseControlStyle(nil);
  2722.                 if (GetCtlValue(ctl)) {
  2723.                     if (GetButtonVariant(ctl) == pushButProc)
  2724.                         OutlineControl(ctl);
  2725.                 }
  2726.             }
  2727.         }
  2728.     }
  2729. }
  2730.  
  2731.  
  2732.  
  2733. /*****************************************************************************/
  2734.  
  2735.  
  2736.  
  2737. /* GetPopupCtlHandle takes a dialog and its item number and (assuming it is a
  2738. ** popup menu control) and returns the control handle for the popup. */
  2739.  
  2740. #pragma segment Controls
  2741. ControlHandle    GetPopupCtlHandle(DialogPtr theDialog, short itemNum)
  2742. {
  2743.     short        theType;
  2744.     Handle        theHndl;
  2745.     Rect        theBox;
  2746.  
  2747.     GetDItem(theDialog, itemNum, &theType, &theHndl, &theBox);
  2748.     return((ControlHandle)theHndl);
  2749. }
  2750.  
  2751.  
  2752.  
  2753. /*****************************************************************************/
  2754.  
  2755.  
  2756.  
  2757. /* GetPopupMenuHandle takes a popup control and returns the menu handle from
  2758. ** the control. */
  2759.  
  2760. #pragma segment Controls
  2761. MenuHandle    GetPopupMenuHandle(ControlHandle popupCtl)
  2762. {
  2763.     PopupCtlDataHandle    popupData;
  2764.  
  2765.     if (popupData = (PopupCtlDataHandle)(*popupCtl)->contrlData)
  2766.         return((*popupData)->mHandle);
  2767.  
  2768.     return(nil);
  2769. }
  2770.  
  2771.  
  2772.  
  2773. /*****************************************************************************/
  2774.  
  2775.  
  2776.  
  2777. /* GetPopupCtlValue returns value for the popup control. */
  2778.  
  2779. #pragma segment Controls
  2780. short    GetPopupCtlValue(DialogPtr theDialog, short popItem)
  2781. {
  2782.     ControlHandle    popupCtl;
  2783.  
  2784.     if (popupCtl = GetPopupCtlHandle(theDialog, popItem))
  2785.         return(GetCtlValue(popupCtl));
  2786.  
  2787.     return(-1);
  2788. }
  2789.  
  2790.  
  2791.  
  2792. /*****************************************************************************/
  2793.  
  2794.  
  2795.  
  2796. /* SetPopupCtlValue makes value the new value for the popup control. */
  2797.  
  2798. #pragma segment Controls
  2799. void    SetPopupCtlValue(DialogPtr theDialog, short popItem, short value)
  2800. {
  2801.     ControlHandle    popupCtl;
  2802.  
  2803.     if (popupCtl = GetPopupCtlHandle(theDialog, popItem)) {
  2804.         (*popupCtl)->contrlValue = value;
  2805.         DoDraw1Control(popupCtl, false);
  2806.     }
  2807. }
  2808.  
  2809.  
  2810.  
  2811. /*****************************************************************************/
  2812. /*****************************************************************************/
  2813. /*****************************************************************************/
  2814.  
  2815.  
  2816.  
  2817. #pragma segment Controls
  2818. OSErr    SetControlStyle(ControlHandle ctl, ControlStyleInfoPtr cinfo)
  2819. {
  2820.     short                len, tlen, ofst;
  2821.     OSErr                err;
  2822.     ControlStyleInfo    cin;
  2823.     Ptr                    ptr1, ptr2;
  2824.  
  2825.     tlen = (*ctl)->contrlTitle[0];
  2826.     ofst = offsetof(ControlRecord,contrlTitle) + tlen + 1;
  2827.     if (!cinfo) {
  2828.         SetHandleSize((Handle)ctl, ofst);
  2829.         return(noErr);
  2830.     }        /* If no info, then control is normalized. */
  2831.  
  2832.     cin   = *cinfo;
  2833.     ptr1  = (Ptr)&cin + offsetof(ControlStyleInfo,font);            /* Point at font. */
  2834.     ptr1 += ptr1[0] + 1;                                            /* Point at packed keyEquivs. */
  2835.     ptr2  = (Ptr)&cin + offsetof(ControlStyleInfo,keyEquivs);        /* Point at keyEquivs. */
  2836.     BlockMove(ptr2, ptr1, ptr2[0] + 1);
  2837.     ptr1 += ptr1[0] + 1;                                            /* Point at packed balloonHelp. */
  2838.     ptr2  = (Ptr)&cin + offsetof(ControlStyleInfo,balloonHelp);        /* Point at balloonHelp. */
  2839.     BlockMove(ptr2, ptr1, ptr2[0] + 1);
  2840.     ptr1 += ptr1[0] + 1;                                            /* Point past packed balloonHelp. */
  2841.  
  2842.     len = ptr1 - (Ptr)&cin;
  2843.     SetHandleSize((Handle)ctl, ofst + len);
  2844.     if (err = MemError()) {
  2845.         SetHandleSize((Handle)ctl, ofst);
  2846.         return(err);
  2847.     }
  2848.  
  2849.     BlockMove((Ptr)&cin, ((Ptr)*ctl) + ofst, len);
  2850.     return(noErr);
  2851. }
  2852.  
  2853.  
  2854.  
  2855. /*****************************************************************************/
  2856.  
  2857.  
  2858.  
  2859. #pragma segment Controls
  2860. Boolean    GetControlStyle(ControlHandle ctl, ControlStyleInfoPtr cinfo)
  2861. {
  2862.     short    clen, tlen, ofst, ofst2, ofst3;
  2863.     Ptr        ptr;
  2864.  
  2865.     clen = GetHandleSize((Handle)ctl);
  2866.     tlen = (*ctl)->contrlTitle[0];
  2867.     ofst = offsetof(ControlRecord,contrlTitle) + tlen + 1;
  2868.     if (clen < ofst + sizeof(short)) return(false);
  2869.  
  2870.     if (cinfo) {
  2871.         ptr = (Ptr)*ctl;
  2872.         BlockMove(ptr + ofst, (Ptr)cinfo, clen - ofst);
  2873.         ptr   = (Ptr)cinfo;
  2874.         ofst  = offsetof(ControlStyleInfo,font);        /* font */
  2875.         ofst2 = ofst  + ptr[ofst]  + 1;                    /* keyEquivs */
  2876.         ofst3 = ofst2 + ptr[ofst2] + 1;                    /* balloonHelp */
  2877.         BlockMove(ptr + ofst3, ptr + offsetof(ControlStyleInfo,balloonHelp), ptr[ofst3] + 1);
  2878.         BlockMove(ptr + ofst2, ptr + offsetof(ControlStyleInfo,keyEquivs),   ptr[ofst2] + 1);
  2879.     }
  2880.  
  2881.     return(true);
  2882. }
  2883.  
  2884.  
  2885.  
  2886. /*****************************************************************************/
  2887.  
  2888.  
  2889.  
  2890. #pragma segment Controls
  2891. short    GetControlID(ControlHandle ctl)
  2892. {
  2893.     short    tlen, ofst, id;
  2894.  
  2895.     tlen = (*ctl)->contrlTitle[0];
  2896.     ofst = offsetof(ControlRecord,contrlTitle) + tlen + 1;
  2897.     if (GetHandleSize((Handle)ctl) < ofst + sizeof(short)) return(0);
  2898.  
  2899.     BlockMove(((Ptr)*ctl) + ofst, &id, sizeof(short));
  2900.     return(id);
  2901. }
  2902.  
  2903.  
  2904.  
  2905. /*****************************************************************************/
  2906.  
  2907.  
  2908.  
  2909. #pragma segment Controls
  2910. void    SetStyledCTitle(ControlHandle ctl, StringPtr title)
  2911. {
  2912.     ControlStyleInfo    cinfo;
  2913.     Boolean                hasStyle;
  2914.  
  2915.     hasStyle = GetControlStyle(ctl, &cinfo);
  2916.     SetCTitle(ctl, title);
  2917.     if (hasStyle)
  2918.         SetControlStyle(ctl, &cinfo);
  2919. }
  2920.  
  2921.  
  2922.  
  2923. /*****************************************************************************/
  2924.  
  2925.  
  2926.  
  2927. #pragma segment Controls
  2928. void    UseControlStyle(ControlHandle ctl)
  2929. {
  2930.     WindowPtr            oldPort;
  2931.     short                fnum;
  2932.     ControlStyleInfo    cinfo;
  2933.     static short        txFont, txSize;
  2934.     static Style        txFace;
  2935.     static WindowPtr    ctlWindow;
  2936.  
  2937.     if (!ctl) {
  2938.         if (ctlWindow) {
  2939.             GetPort(&oldPort);
  2940.             SetPort(ctlWindow);
  2941.             TextFont(txFont);
  2942.             TextSize(txSize);
  2943.             TextFace(txFace);
  2944.             SetPort(oldPort);
  2945.         }
  2946.         return;
  2947.     }
  2948.  
  2949.     ctlWindow = nil;
  2950.     if (GetCVariant(ctl) & useWFont) {
  2951.         if (GetControlStyle(ctl, &cinfo)) {
  2952.             GetPort(&oldPort);
  2953.             SetPort(ctlWindow = (*ctl)->contrlOwner);
  2954.             txFont = ctlWindow->txFont;
  2955.             txSize = ctlWindow->txSize;
  2956.             txFace = ctlWindow->txFace;
  2957.             TextFace(cinfo.fontStyle);
  2958.             fnum = 0;
  2959.             if (cinfo.font[0])
  2960.                 GetFNum(cinfo.font, &fnum);
  2961.             TextFont(fnum);
  2962.             TextSize(cinfo.fontSize);
  2963.             SetPort(oldPort);
  2964.         }
  2965.     }
  2966. }
  2967.  
  2968.  
  2969.  
  2970. /*****************************************************************************/
  2971. /*****************************************************************************/
  2972. /*****************************************************************************/
  2973.  
  2974.  
  2975.  
  2976. #pragma segment Controls
  2977. Boolean    ControlKeyEquiv(WindowPtr window, EventRecord *event, ControlHandle *retCtl, StringPtr defaultEquivs)
  2978. {
  2979.     ControlHandle        ctl;
  2980.     ControlStyleInfo    cinfo;
  2981.     short                i, theChr, cc, theMod, equivChr, modMask, modVal, pass;
  2982.  
  2983.     if (retCtl)
  2984.         *retCtl = nil;
  2985.  
  2986.     if (event->what != keyDown) return(false);
  2987.  
  2988.     theChr = event->message   & charCodeMask;
  2989.     theMod = event->modifiers & keyCodeMask;
  2990.  
  2991.     for (pass = 0; pass < 2; ++pass) {
  2992.         for (ctl = ((WindowPeek)window)->controlList; ctl; ctl = (*ctl)->nextControl) {
  2993.             if (!(*ctl)->contrlVis)   continue;        /* Control not visible, so next control. */
  2994.             if ((*ctl)->contrlHilite) continue;        /* Control not active, so next control. */
  2995.             cinfo.keyEquivs[0] = 0;
  2996.             switch (pass) {
  2997.                 case 0:
  2998.                     GetControlStyle(ctl, &cinfo);
  2999.                     break;
  3000.                 case 1:
  3001.                     if (GetButtonVariant(ctl) == pushButProc)                /* If simple button... */
  3002.                         if (GetCtlValue(ctl))                                /* If is outlined button... */
  3003.                             if (defaultEquivs)                                /* If default equiv text passed in... */
  3004.                                 pcpy(cinfo.keyEquivs, defaultEquivs)    ;    /* Use it. */
  3005.                     break;
  3006.             }
  3007.             for (i = 1; i < cinfo.keyEquivs[0]; i += 7) {
  3008.                 if (cinfo.keyEquivs[i] == (unsigned char)':') break;
  3009.                 cc = theChr;
  3010.                 if (cinfo.keyEquivs[i] == (unsigned char)'≈')
  3011.                     if ((cc >= 'a') && (cc <= 'z')) cc -= 32;
  3012.                 equivChr = GetHexByte((char *)(cinfo.keyEquivs + i));
  3013.                 modMask  = GetHexByte((char *)(cinfo.keyEquivs + i + 2)) << 8;
  3014.                 modVal   = GetHexByte((char *)(cinfo.keyEquivs + i + 4)) << 8;
  3015.                 if (cc == equivChr) {
  3016.                     if ((theMod & modMask) == modVal) {
  3017.                         if (retCtl)
  3018.                             *retCtl = ctl;
  3019.                         return(true);
  3020.                     }
  3021.                 }
  3022.             }
  3023.         }
  3024.     }
  3025.  
  3026.     return(false);
  3027. }
  3028.  
  3029.  
  3030.  
  3031.